diff options
author | Rodney W. Grimes <rgrimes@FreeBSD.org> | 1993-06-12 14:58:17 +0000 |
---|---|---|
committer | Rodney W. Grimes <rgrimes@FreeBSD.org> | 1993-06-12 14:58:17 +0000 |
commit | 5b81b6b301437eb9a6df491c829475bd29ae5d6c (patch) | |
tree | de2d7c6726a45428d4a310da2acd8839daf9f85f /sys | |
parent | 9002c02abc587664acb357c6879d8ca08664dd0b (diff) | |
download | src-test2-5b81b6b301437eb9a6df491c829475bd29ae5d6c.tar.gz src-test2-5b81b6b301437eb9a6df491c829475bd29ae5d6c.zip |
Notes
Diffstat (limited to 'sys')
227 files changed, 75332 insertions, 0 deletions
diff --git a/sys/alpha/include/pc/display.h b/sys/alpha/include/pc/display.h new file mode 100644 index 000000000000..cab46e44e881 --- /dev/null +++ b/sys/alpha/include/pc/display.h @@ -0,0 +1,43 @@ +/* + * 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 + +/* 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 + +/* 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/alpha/include/pc/msdos.h b/sys/alpha/include/pc/msdos.h new file mode 100644 index 000000000000..8d1eb7bfd52d --- /dev/null +++ b/sys/alpha/include/pc/msdos.h @@ -0,0 +1,63 @@ +/* + * msdos common header file + * [obtained from mtools -wfj] + * how to decipher DOS disk structures in coexisting with DOS + */ + +#define MSECTOR_SIZE 512 /* MSDOS sector size in bytes */ +#define MDIR_SIZE 32 /* MSDOS directory size in bytes */ +#define MAX_CLUSTER 8192 /* largest cluster size */ +#define MAX_PATH 128 /* largest MSDOS path length */ +#define MAX_DIR_SECS 64 /* largest directory (in sectors) */ + +#define NEW 1 +#define OLD 0 + +struct directory { + unsigned char name[8]; /* file name */ + unsigned char ext[3]; /* file extension */ + unsigned char attr; /* attribute byte */ + unsigned char reserved[10]; /* ?? */ + unsigned char time[2]; /* time stamp */ + unsigned char date[2]; /* date stamp */ + unsigned char start[2]; /* starting cluster number */ + unsigned char size[4]; /* size of the file */ +}; + +struct bootsector { + unsigned char jump[3]; /* Jump to boot code */ + unsigned char banner[8]; /* OEM name & version */ + unsigned char secsiz[2]; /* Bytes per sector hopefully 512 */ + unsigned char clsiz; /* Cluster size in sectors */ + unsigned char nrsvsect[2]; /* Number of reserved (boot) sectors */ + unsigned char nfat; /* Number of FAT tables hopefully 2 */ + unsigned char dirents[2]; /* Number of directory slots */ + unsigned char psect[2]; /* Total sectors on disk */ + unsigned char descr; /* Media descriptor=first byte of FAT */ + unsigned char fatlen[2]; /* Sectors in FAT */ + unsigned char nsect[2]; /* Sectors/track */ + unsigned char nheads[2]; /* Heads */ + unsigned char nhs[4]; /* number of hidden sectors */ + unsigned char bigsect[4]; /* big total sectors */ + unsigned char junk[476]; /* who cares? */ +}; + +/* DOS partition table -- located in boot block */ + +#define DOSBBSECTOR 0 /* DOS boot block relative sector number */ +#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 */ +#define DOSPTYP_386BSD 0xa5 /* 386BSD partition type */ + 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]; diff --git a/sys/amd64/Makefile b/sys/amd64/Makefile new file mode 100644 index 000000000000..0662e28ce8ac --- /dev/null +++ b/sys/amd64/Makefile @@ -0,0 +1,24 @@ +# @(#)Makefile 7.3 (Berkeley) 6/9/91 + +# Makefile for i386 tags file + +all: + @echo "make tags or links only" + +TI386= ../i386/tags +SI386= ../i386/i386/*.[ch] ../i386/include/*.h ../i386/isa/*.[ch] +AI386= ../i386/i386/*.s + +# Directories in which to place i386 tags links +DI386= eisa isa mca include + +tags: + -ctags -dtf ${TI386} ${COMM} ${SI386} + egrep "^ENTRY(.*)|^ALTENTRY(.*)" ${AI386} | \ + sed "s;\([^:]*\):\([^(]*\)(\([^, )]*\)\(.*\);\3 \1 /^\2(\3\4$$/;" \ + >> ${TI386} + sort -o ${TI386} ${TI386} + +links: + -for i in ${DI386}; do \ + cd $$i && rm -f tags; ln -s ../tags tags; done diff --git a/sys/amd64/amd64/autoconf.c b/sys/amd64/amd64/autoconf.c new file mode 100644 index 000000000000..7eee991a9466 --- /dev/null +++ b/sys/amd64/amd64/autoconf.c @@ -0,0 +1,213 @@ +/*- + * 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. + * + * @(#)autoconf.c 7.1 (Berkeley) 5/9/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00117 + * -------------------- ----- ---------------------- + * + * 09 Apr 93 ???(From sun-lamp) Fix to report sd when Julians + * scsi code is used, allow you to swap + * root floppies during a boot + */ +static char rcsid[] = "$Header: /b/source/CVS/src/sys.386bsd/i386/i386/autoconf.c,v 1.3 1993/04/10 21:58:52 cgd Exp $"; + +/* + * Setup the system to run on the current machine. + * + * Configure() is called at boot time and initializes the vba + * device tables and the memory controller monitoring. Available + * devices are determined (from possibilities mentioned in ioconf.c), + * and the drivers are initialized. + */ +#include "param.h" +#include "systm.h" +#include "buf.h" +#include "dkstat.h" +#include "conf.h" +#include "dmap.h" +#include "reboot.h" + +#include "machine/pte.h" + +/* + * The following several variables are related to + * the configuration process, and are used in initializing + * the machine. + */ +int dkn; /* number of iostat dk numbers assigned so far */ +extern int cold; /* cold start flag initialized in locore.s */ + +/* + * Determine i/o configuration for a machine. + */ +configure() +{ + +#include "isa.h" +#if NISA > 0 + isa_configure(); +#endif + +#if GENERICxxx + if ((boothowto & RB_ASKNAME) == 0) + setroot(); + setconf(); +#else + setroot(); +#endif + /* + * Configure swap area and related system + * parameter based on device(s) used. + */ + swapconf(); + cold = 0; +} + +/* + * Configure swap space and related parameters. + */ +swapconf() +{ + register struct swdevt *swp; + register int nblks; +extern int Maxmem; + + for (swp = swdevt; swp->sw_dev > 0; swp++) + { + unsigned d = major(swp->sw_dev); + + if (d > nblkdev) break; + if (bdevsw[d].d_psize) { + nblks = (*bdevsw[d].d_psize)(swp->sw_dev); + if (nblks > 0 && + (swp->sw_nblks == 0 || swp->sw_nblks > nblks)) + swp->sw_nblks = nblks; + else + swp->sw_nblks = 0; + } + swp->sw_nblks = ctod(dtoc(swp->sw_nblks)); + } + if (dumplo == 0 && bdevsw[major(dumpdev)].d_psize) + /*dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) - physmem;*/ + dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) - + Maxmem*NBPG/512; + if (dumplo < 0) + dumplo = 0; +} + +#define DOSWAP /* change swdevt and dumpdev */ +u_long bootdev = 0; /* should be dev_t, but not until 32 bits */ + +#include "sd.h" +static char devname[][2] = { + 'w','d', /* 0 = wd */ + 's','w', /* 1 = sw */ + 'f','d', /* 2 = fd */ + 'w','t', /* 3 = wt */ +#if NSD < 1 + 'a','s', /* 4 = as */ +#else + 's','d', /* 4 = sd -- new SCSI system */ +#endif +}; + +#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, adaptor; + dev_t temp, orootdev; + struct swdevt *swp; + +/*printf("howto %x bootdev %x ", boothowto, bootdev);*/ + if (boothowto & RB_DFLTROOT || + (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC) + return; + majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK; + if (majdev > sizeof(devname) / sizeof(devname[0])) + return; + adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK; + part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK; + unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK; + 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; + if (devname[majdev][0] == 'f' && devname[majdev][1] == 'd') { + printf(""); + printf("* insert the floppy you want to have mounted as\n"); + printf("* root, and hit any key to continue booting:\n"); + cngetc(); + printf(""); + } + printf("changing root device to %c%c%d%c\n", + devname[majdev][0], devname[majdev][1], + mindev >> PARTITIONSHIFT, part + 'a'); +#ifdef DOSWAP + mindev &= ~PARTITIONMASK; + for (swp = swdevt; swp->sw_dev; swp++) { + if (majdev == major(swp->sw_dev) && + mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) { + + temp = swdevt[0].sw_dev; + swdevt[0].sw_dev = swp->sw_dev; + swp->sw_dev = temp; + break; + } + } + if (swp->sw_dev == 0) + 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 +} diff --git a/sys/amd64/amd64/db_disasm.c b/sys/amd64/amd64/db_disasm.c new file mode 100644 index 000000000000..20430b674133 --- /dev/null +++ b/sys/amd64/amd64/db_disasm.c @@ -0,0 +1,1397 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_disasm.c,v $ + * Revision 1.1 1992/03/25 21:42:01 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:11:03 mrt + * Changed to new Mach copyright + * [91/02/01 17:31:03 mrt] + * + * Revision 2.2 90/08/27 21:55:56 dbg + * Fix register operand for move to/from control/test/debug + * register instructions. Add i486 instructions. + * [90/08/27 dbg] + * + * Import db_sym.h. Print instruction displacements in + * current radix (signed). Change calling sequence of + * db_disasm. + * [90/08/21 dbg] + * Fix includes. + * [90/08/08 dbg] + * Created. + * [90/07/25 dbg] + * + */ + +/* + * Instruction disassembler. + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> + +#include <ddb/db_access.h> +#include <ddb/db_sym.h> + +/* + * Size attributes + */ +#define BYTE 0 +#define WORD 1 +#define LONG 2 +#define QUAD 3 +#define SNGL 4 +#define DBLR 5 +#define EXTR 6 +#define SDEP 7 +#define NONE 8 + +/* + * Addressing modes + */ +#define E 1 /* general effective address */ +#define Eind 2 /* indirect address (jump, call) */ +#define Ew 3 /* address, word size */ +#define Eb 4 /* address, byte size */ +#define R 5 /* register, in 'reg' field */ +#define Rw 6 /* word register, in 'reg' field */ +#define Ri 7 /* register in instruction */ +#define S 8 /* segment reg, in 'reg' field */ +#define Si 9 /* segment reg, in instruction */ +#define A 10 /* accumulator */ +#define BX 11 /* (bx) */ +#define CL 12 /* cl, for shifts */ +#define DX 13 /* dx, for IO */ +#define SI 14 /* si */ +#define DI 15 /* di */ +#define CR 16 /* control register */ +#define DR 17 /* debug register */ +#define TR 18 /* test register */ +#define I 19 /* immediate, unsigned */ +#define Is 20 /* immediate, signed */ +#define Ib 21 /* byte immediate, unsigned */ +#define Ibs 22 /* byte immediate, signed */ +#define Iw 23 /* word immediate, unsigned */ +#define Il 24 /* long immediate */ +#define O 25 /* direct address */ +#define Db 26 /* byte displacement from EIP */ +#define Dl 27 /* long displacement from EIP */ +#define o1 28 /* constant 1 */ +#define o3 29 /* constant 3 */ +#define OS 30 /* immediate offset/segment */ +#define ST 31 /* FP stack top */ +#define STI 32 /* FP stack */ +#define X 33 /* extended FP op */ +#define XA 34 /* for 'fstcw %ax' */ + +struct inst { + char * i_name; /* name */ + short i_has_modrm; /* has regmodrm byte */ + short i_size; /* operand size */ + int i_mode; /* addressing modes */ + char * i_extra; /* pointer to extra opcode table */ +}; + +#define op1(x) (x) +#define op2(x,y) ((x)|((y)<<8)) +#define op3(x,y,z) ((x)|((y)<<8)|((z)<<16)) + +struct finst { + char * f_name; /* name for memory instruction */ + int f_size; /* size for memory instruction */ + int f_rrmode; /* mode for rr instruction */ + char * f_rrname; /* name for rr instruction + (or pointer to table) */ +}; + +char * db_Grp6[] = { + "sldt", + "str", + "lldt", + "ltr", + "verr", + "verw", + "", + "" +}; + +char * db_Grp7[] = { + "sgdt", + "sidt", + "lgdt", + "lidt", + "smsw", + "", + "lmsw", + "invlpg" +}; + +char * db_Grp8[] = { + "", + "", + "", + "", + "bt", + "bts", + "btr", + "btc" +}; + +struct inst db_inst_0f0x[] = { +/*00*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp6 }, +/*01*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp7 }, +/*02*/ { "lar", TRUE, LONG, op2(E,R), 0 }, +/*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 }, +/*04*/ { "", FALSE, NONE, 0, 0 }, +/*05*/ { "", FALSE, NONE, 0, 0 }, +/*06*/ { "clts", FALSE, NONE, 0, 0 }, +/*07*/ { "", FALSE, NONE, 0, 0 }, + +/*08*/ { "invd", FALSE, NONE, 0, 0 }, +/*09*/ { "wbinvd",FALSE, NONE, 0, 0 }, +/*0a*/ { "", FALSE, NONE, 0, 0 }, +/*0b*/ { "", FALSE, NONE, 0, 0 }, +/*0c*/ { "", FALSE, NONE, 0, 0 }, +/*0d*/ { "", FALSE, NONE, 0, 0 }, +/*0e*/ { "", FALSE, NONE, 0, 0 }, +/*0f*/ { "", FALSE, NONE, 0, 0 }, +}; + +struct inst db_inst_0f2x[] = { +/*20*/ { "mov", TRUE, LONG, op2(CR,E), 0 }, /* use E for reg */ +/*21*/ { "mov", TRUE, LONG, op2(DR,E), 0 }, /* since mod == 11 */ +/*22*/ { "mov", TRUE, LONG, op2(E,CR), 0 }, +/*23*/ { "mov", TRUE, LONG, op2(E,DR), 0 }, +/*24*/ { "mov", TRUE, LONG, op2(TR,E), 0 }, +/*25*/ { "", FALSE, NONE, 0, 0 }, +/*26*/ { "mov", TRUE, LONG, op2(E,TR), 0 }, +/*27*/ { "", FALSE, NONE, 0, 0 }, + +/*28*/ { "", FALSE, NONE, 0, 0 }, +/*29*/ { "", FALSE, NONE, 0, 0 }, +/*2a*/ { "", FALSE, NONE, 0, 0 }, +/*2b*/ { "", FALSE, NONE, 0, 0 }, +/*2c*/ { "", FALSE, NONE, 0, 0 }, +/*2d*/ { "", FALSE, NONE, 0, 0 }, +/*2e*/ { "", FALSE, NONE, 0, 0 }, +/*2f*/ { "", FALSE, NONE, 0, 0 }, +}; + +struct inst db_inst_0f8x[] = { +/*80*/ { "jo", FALSE, NONE, op1(Dl), 0 }, +/*81*/ { "jno", FALSE, NONE, op1(Dl), 0 }, +/*82*/ { "jb", FALSE, NONE, op1(Dl), 0 }, +/*83*/ { "jnb", FALSE, NONE, op1(Dl), 0 }, +/*84*/ { "jz", FALSE, NONE, op1(Dl), 0 }, +/*85*/ { "jnz", FALSE, NONE, op1(Dl), 0 }, +/*86*/ { "jbe", FALSE, NONE, op1(Dl), 0 }, +/*87*/ { "jnbe", FALSE, NONE, op1(Dl), 0 }, + +/*88*/ { "js", FALSE, NONE, op1(Dl), 0 }, +/*89*/ { "jns", FALSE, NONE, op1(Dl), 0 }, +/*8a*/ { "jp", FALSE, NONE, op1(Dl), 0 }, +/*8b*/ { "jnp", FALSE, NONE, op1(Dl), 0 }, +/*8c*/ { "jl", FALSE, NONE, op1(Dl), 0 }, +/*8d*/ { "jnl", FALSE, NONE, op1(Dl), 0 }, +/*8e*/ { "jle", FALSE, NONE, op1(Dl), 0 }, +/*8f*/ { "jnle", FALSE, NONE, op1(Dl), 0 }, +}; + +struct inst db_inst_0f9x[] = { +/*90*/ { "seto", TRUE, NONE, op1(Eb), 0 }, +/*91*/ { "setno", TRUE, NONE, op1(Eb), 0 }, +/*92*/ { "setb", TRUE, NONE, op1(Eb), 0 }, +/*93*/ { "setnb", TRUE, NONE, op1(Eb), 0 }, +/*94*/ { "setz", TRUE, NONE, op1(Eb), 0 }, +/*95*/ { "setnz", TRUE, NONE, op1(Eb), 0 }, +/*96*/ { "setbe", TRUE, NONE, op1(Eb), 0 }, +/*97*/ { "setnbe",TRUE, NONE, op1(Eb), 0 }, + +/*98*/ { "sets", TRUE, NONE, op1(Eb), 0 }, +/*99*/ { "setns", TRUE, NONE, op1(Eb), 0 }, +/*9a*/ { "setp", TRUE, NONE, op1(Eb), 0 }, +/*9b*/ { "setnp", TRUE, NONE, op1(Eb), 0 }, +/*9c*/ { "setl", TRUE, NONE, op1(Eb), 0 }, +/*9d*/ { "setnl", TRUE, NONE, op1(Eb), 0 }, +/*9e*/ { "setle", TRUE, NONE, op1(Eb), 0 }, +/*9f*/ { "setnle",TRUE, NONE, op1(Eb), 0 }, +}; + +struct inst db_inst_0fax[] = { +/*a0*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*a1*/ { "pop", FALSE, NONE, op1(Si), 0 }, +/*a2*/ { "", FALSE, NONE, 0, 0 }, +/*a3*/ { "bt", TRUE, LONG, op2(E,R), 0 }, +/*a4*/ { "shld", TRUE, LONG, op3(Ib,E,R), 0 }, +/*a5*/ { "shld", TRUE, LONG, op3(CL,E,R), 0 }, +/*a6*/ { "", FALSE, NONE, 0, 0 }, +/*a7*/ { "", FALSE, NONE, 0, 0 }, + +/*a8*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*a9*/ { "pop", FALSE, NONE, op1(Si), 0 }, +/*aa*/ { "", FALSE, NONE, 0, 0 }, +/*ab*/ { "bts", TRUE, LONG, op2(E,R), 0 }, +/*ac*/ { "shrd", TRUE, LONG, op3(Ib,E,R), 0 }, +/*ad*/ { "shrd", TRUE, LONG, op3(CL,E,R), 0 }, +/*a6*/ { "", FALSE, NONE, 0, 0 }, +/*a7*/ { "imul", TRUE, LONG, op2(E,R), 0 }, +}; + +struct inst db_inst_0fbx[] = { +/*b0*/ { "", FALSE, NONE, 0, 0 }, +/*b1*/ { "", FALSE, NONE, 0, 0 }, +/*b2*/ { "lss", TRUE, LONG, op2(E, R), 0 }, +/*b3*/ { "bts", TRUE, LONG, op2(R, E), 0 }, +/*b4*/ { "lfs", TRUE, LONG, op2(E, R), 0 }, +/*b5*/ { "lgs", TRUE, LONG, op2(E, R), 0 }, +/*b6*/ { "movzb", TRUE, LONG, op2(E, R), 0 }, +/*b7*/ { "movzw", TRUE, LONG, op2(E, R), 0 }, + +/*b8*/ { "", FALSE, NONE, 0, 0 }, +/*b9*/ { "", FALSE, NONE, 0, 0 }, +/*ba*/ { "", TRUE, LONG, op2(Is, E), (char *)db_Grp8 }, +/*bb*/ { "btc", TRUE, LONG, op2(R, E), 0 }, +/*bc*/ { "bsf", TRUE, LONG, op2(E, R), 0 }, +/*bd*/ { "bsr", TRUE, LONG, op2(E, R), 0 }, +/*be*/ { "movsb", TRUE, LONG, op2(E, R), 0 }, +/*bf*/ { "movsw", TRUE, LONG, op2(E, R), 0 }, +}; + +struct inst db_inst_0fcx[] = { +/*c0*/ { "xadd", TRUE, BYTE, op2(R, E), 0 }, +/*c1*/ { "xadd", TRUE, LONG, op2(R, E), 0 }, +/*c2*/ { "", FALSE, NONE, 0, 0 }, +/*c3*/ { "", FALSE, NONE, 0, 0 }, +/*c4*/ { "", FALSE, NONE, 0, 0 }, +/*c5*/ { "", FALSE, NONE, 0, 0 }, +/*c6*/ { "", FALSE, NONE, 0, 0 }, +/*c7*/ { "", FALSE, NONE, 0, 0 }, +/*c8*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*c9*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*ca*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*cb*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*cc*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*cd*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*ce*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*cf*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +}; + +struct inst db_inst_0fdx[] = { +/*c0*/ { "cmpxchg",TRUE, BYTE, op2(R, E), 0 }, +/*c1*/ { "cmpxchg",TRUE, LONG, op2(R, E), 0 }, +/*c2*/ { "", FALSE, NONE, 0, 0 }, +/*c3*/ { "", FALSE, NONE, 0, 0 }, +/*c4*/ { "", FALSE, NONE, 0, 0 }, +/*c5*/ { "", FALSE, NONE, 0, 0 }, +/*c6*/ { "", FALSE, NONE, 0, 0 }, +/*c7*/ { "", FALSE, NONE, 0, 0 }, +/*c8*/ { "", FALSE, NONE, 0, 0 }, +/*c9*/ { "", FALSE, NONE, 0, 0 }, +/*ca*/ { "", FALSE, NONE, 0, 0 }, +/*cb*/ { "", FALSE, NONE, 0, 0 }, +/*cc*/ { "", FALSE, NONE, 0, 0 }, +/*cd*/ { "", FALSE, NONE, 0, 0 }, +/*ce*/ { "", FALSE, NONE, 0, 0 }, +/*cf*/ { "", FALSE, NONE, 0, 0 }, +}; + +struct inst *db_inst_0f[] = { + db_inst_0f0x, + 0, + db_inst_0f2x, + 0, + 0, + 0, + 0, + 0, + db_inst_0f8x, + db_inst_0f9x, + db_inst_0fax, + db_inst_0fbx, + db_inst_0fcx, + db_inst_0fdx, + 0, + 0 +}; + +char * db_Esc92[] = { + "fnop", "", "", "", "", "", "", "" +}; +char * db_Esc93[] = { + "", "", "", "", "", "", "", "" +}; +char * db_Esc94[] = { + "fchs", "fabs", "", "", "ftst", "fxam", "", "" +}; +char * db_Esc95[] = { + "fld1", "fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","" +}; +char * db_Esc96[] = { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp", + "fincstp" +}; +char * db_Esc97[] = { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos" +}; + +char * db_Esca4[] = { + "", "fucompp","", "", "", "", "", "" +}; + +char * db_Escb4[] = { + "", "", "fnclex","fninit","", "", "", "" +}; + +char * db_Esce3[] = { + "", "fcompp","", "", "", "", "", "" +}; + +char * db_Escf4[] = { + "fnstsw","", "", "", "", "", "", "" +}; + +struct finst db_Esc8[] = { +/*0*/ { "fadd", SNGL, op2(STI,ST), 0 }, +/*1*/ { "fmul", SNGL, op2(STI,ST), 0 }, +/*2*/ { "fcom", SNGL, op2(STI,ST), 0 }, +/*3*/ { "fcomp", SNGL, op2(STI,ST), 0 }, +/*4*/ { "fsub", SNGL, op2(STI,ST), 0 }, +/*5*/ { "fsubr", SNGL, op2(STI,ST), 0 }, +/*6*/ { "fdiv", SNGL, op2(STI,ST), 0 }, +/*7*/ { "fdivr", SNGL, op2(STI,ST), 0 }, +}; + +struct finst db_Esc9[] = { +/*0*/ { "fld", SNGL, op1(STI), 0 }, +/*1*/ { "", NONE, op1(STI), "fxch" }, +/*2*/ { "fst", SNGL, op1(X), (char *)db_Esc92 }, +/*3*/ { "fstp", SNGL, op1(X), (char *)db_Esc93 }, +/*4*/ { "fldenv", NONE, op1(X), (char *)db_Esc94 }, +/*5*/ { "fldcw", NONE, op1(X), (char *)db_Esc95 }, +/*6*/ { "fnstenv",NONE, op1(X), (char *)db_Esc96 }, +/*7*/ { "fnstcw", NONE, op1(X), (char *)db_Esc97 }, +}; + +struct finst db_Esca[] = { +/*0*/ { "fiadd", WORD, 0, 0 }, +/*1*/ { "fimul", WORD, 0, 0 }, +/*2*/ { "ficom", WORD, 0, 0 }, +/*3*/ { "ficomp", WORD, 0, 0 }, +/*4*/ { "fisub", WORD, op1(X), (char *)db_Esca4 }, +/*5*/ { "fisubr", WORD, 0, 0 }, +/*6*/ { "fidiv", WORD, 0, 0 }, +/*7*/ { "fidivr", WORD, 0, 0 } +}; + +struct finst db_Escb[] = { +/*0*/ { "fild", WORD, 0, 0 }, +/*1*/ { "", NONE, 0, 0 }, +/*2*/ { "fist", WORD, 0, 0 }, +/*3*/ { "fistp", WORD, 0, 0 }, +/*4*/ { "", WORD, op1(X), (char *)db_Escb4 }, +/*5*/ { "fld", EXTR, 0, 0 }, +/*6*/ { "", WORD, 0, 0 }, +/*7*/ { "fstp", EXTR, 0, 0 }, +}; + +struct finst db_Escc[] = { +/*0*/ { "fadd", DBLR, op2(ST,STI), 0 }, +/*1*/ { "fmul", DBLR, op2(ST,STI), 0 }, +/*2*/ { "fcom", DBLR, op2(ST,STI), 0 }, +/*3*/ { "fcomp", DBLR, op2(ST,STI), 0 }, +/*4*/ { "fsub", DBLR, op2(ST,STI), "fsubr" }, +/*5*/ { "fsubr", DBLR, op2(ST,STI), "fsub" }, +/*6*/ { "fdiv", DBLR, op2(ST,STI), "fdivr" }, +/*7*/ { "fdivr", DBLR, op2(ST,STI), "fdiv" }, +}; + +struct finst db_Escd[] = { +/*0*/ { "fld", DBLR, op1(STI), "ffree" }, +/*1*/ { "", NONE, 0, 0 }, +/*2*/ { "fst", DBLR, op1(STI), 0 }, +/*3*/ { "fstp", DBLR, op1(STI), 0 }, +/*4*/ { "frstor", NONE, op1(STI), "fucom" }, +/*5*/ { "", NONE, op1(STI), "fucomp" }, +/*6*/ { "fnsave", NONE, 0, 0 }, +/*7*/ { "fnstsw", NONE, 0, 0 }, +}; + +struct finst db_Esce[] = { +/*0*/ { "fiadd", LONG, op2(ST,STI), "faddp" }, +/*1*/ { "fimul", LONG, op2(ST,STI), "fmulp" }, +/*2*/ { "ficom", LONG, 0, 0 }, +/*3*/ { "ficomp", LONG, op1(X), (char *)db_Esce3 }, +/*4*/ { "fisub", LONG, op2(ST,STI), "fsubrp" }, +/*5*/ { "fisubr", LONG, op2(ST,STI), "fsubp" }, +/*6*/ { "fidiv", LONG, op2(ST,STI), "fdivrp" }, +/*7*/ { "fidivr", LONG, op2(ST,STI), "fdivp" }, +}; + +struct finst db_Escf[] = { +/*0*/ { "fild", LONG, 0, 0 }, +/*1*/ { "", LONG, 0, 0 }, +/*2*/ { "fist", LONG, 0, 0 }, +/*3*/ { "fistp", LONG, 0, 0 }, +/*4*/ { "fbld", NONE, op1(XA), (char *)db_Escf4 }, +/*5*/ { "fld", QUAD, 0, 0 }, +/*6*/ { "fbstp", NONE, 0, 0 }, +/*7*/ { "fstp", QUAD, 0, 0 }, +}; + +struct finst *db_Esc_inst[] = { + db_Esc8, db_Esc9, db_Esca, db_Escb, + db_Escc, db_Escd, db_Esce, db_Escf +}; + +char * db_Grp1[] = { + "add", + "or", + "adc", + "sbb", + "and", + "sub", + "xor", + "cmp" +}; + +char * db_Grp2[] = { + "rol", + "ror", + "rcl", + "rcr", + "shl", + "shr", + "shl", + "sar" +}; + +struct inst db_Grp3[] = { + { "test", TRUE, NONE, op2(I,E), 0 }, + { "test", TRUE, NONE, op2(I,E), 0 }, + { "not", TRUE, NONE, op1(E), 0 }, + { "neg", TRUE, NONE, op1(E), 0 }, + { "mul", TRUE, NONE, op2(E,A), 0 }, + { "imul", TRUE, NONE, op2(E,A), 0 }, + { "div", TRUE, NONE, op2(E,A), 0 }, + { "idiv", TRUE, NONE, op2(E,A), 0 }, +}; + +struct inst db_Grp4[] = { + { "inc", TRUE, BYTE, op1(E), 0 }, + { "dec", TRUE, BYTE, op1(E), 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 } +}; + +struct inst db_Grp5[] = { + { "inc", TRUE, LONG, op1(E), 0 }, + { "dec", TRUE, LONG, op1(E), 0 }, + { "call", TRUE, NONE, op1(Eind),0 }, + { "lcall", TRUE, NONE, op1(Eind),0 }, + { "jmp", TRUE, NONE, op1(Eind),0 }, + { "ljmp", TRUE, NONE, op1(Eind),0 }, + { "push", TRUE, LONG, op1(E), 0 }, + { "", TRUE, NONE, 0, 0 } +}; + +struct inst db_inst_table[256] = { +/*00*/ { "add", TRUE, BYTE, op2(R, E), 0 }, +/*01*/ { "add", TRUE, LONG, op2(R, E), 0 }, +/*02*/ { "add", TRUE, BYTE, op2(E, R), 0 }, +/*03*/ { "add", TRUE, LONG, op2(E, R), 0 }, +/*04*/ { "add", FALSE, BYTE, op2(Is, A), 0 }, +/*05*/ { "add", FALSE, LONG, op2(Is, A), 0 }, +/*06*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*07*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*08*/ { "or", TRUE, BYTE, op2(R, E), 0 }, +/*09*/ { "or", TRUE, LONG, op2(R, E), 0 }, +/*0a*/ { "or", TRUE, BYTE, op2(E, R), 0 }, +/*0b*/ { "or", TRUE, LONG, op2(E, R), 0 }, +/*0c*/ { "or", FALSE, BYTE, op2(I, A), 0 }, +/*0d*/ { "or", FALSE, LONG, op2(I, A), 0 }, +/*0e*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*0f*/ { "", FALSE, NONE, 0, 0 }, + +/*10*/ { "adc", TRUE, BYTE, op2(R, E), 0 }, +/*11*/ { "adc", TRUE, LONG, op2(R, E), 0 }, +/*12*/ { "adc", TRUE, BYTE, op2(E, R), 0 }, +/*13*/ { "adc", TRUE, LONG, op2(E, R), 0 }, +/*14*/ { "adc", FALSE, BYTE, op2(Is, A), 0 }, +/*15*/ { "adc", FALSE, LONG, op2(Is, A), 0 }, +/*16*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*17*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*18*/ { "sbb", TRUE, BYTE, op2(R, E), 0 }, +/*19*/ { "sbb", TRUE, LONG, op2(R, E), 0 }, +/*1a*/ { "sbb", TRUE, BYTE, op2(E, R), 0 }, +/*1b*/ { "sbb", TRUE, LONG, op2(E, R), 0 }, +/*1c*/ { "sbb", FALSE, BYTE, op2(Is, A), 0 }, +/*1d*/ { "sbb", FALSE, LONG, op2(Is, A), 0 }, +/*1e*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*1f*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*20*/ { "and", TRUE, BYTE, op2(R, E), 0 }, +/*21*/ { "and", TRUE, LONG, op2(R, E), 0 }, +/*22*/ { "and", TRUE, BYTE, op2(E, R), 0 }, +/*23*/ { "and", TRUE, LONG, op2(E, R), 0 }, +/*24*/ { "and", FALSE, BYTE, op2(I, A), 0 }, +/*25*/ { "and", FALSE, LONG, op2(I, A), 0 }, +/*26*/ { "", FALSE, NONE, 0, 0 }, +/*27*/ { "aaa", FALSE, NONE, 0, 0 }, + +/*28*/ { "sub", TRUE, BYTE, op2(R, E), 0 }, +/*29*/ { "sub", TRUE, LONG, op2(R, E), 0 }, +/*2a*/ { "sub", TRUE, BYTE, op2(E, R), 0 }, +/*2b*/ { "sub", TRUE, LONG, op2(E, R), 0 }, +/*2c*/ { "sub", FALSE, BYTE, op2(Is, A), 0 }, +/*2d*/ { "sub", FALSE, LONG, op2(Is, A), 0 }, +/*2e*/ { "", FALSE, NONE, 0, 0 }, +/*2f*/ { "das", FALSE, NONE, 0, 0 }, + +/*30*/ { "xor", TRUE, BYTE, op2(R, E), 0 }, +/*31*/ { "xor", TRUE, LONG, op2(R, E), 0 }, +/*32*/ { "xor", TRUE, BYTE, op2(E, R), 0 }, +/*33*/ { "xor", TRUE, LONG, op2(E, R), 0 }, +/*34*/ { "xor", FALSE, BYTE, op2(I, A), 0 }, +/*35*/ { "xor", FALSE, LONG, op2(I, A), 0 }, +/*36*/ { "", FALSE, NONE, 0, 0 }, +/*37*/ { "daa", FALSE, NONE, 0, 0 }, + +/*38*/ { "cmp", TRUE, BYTE, op2(R, E), 0 }, +/*39*/ { "cmp", TRUE, LONG, op2(R, E), 0 }, +/*3a*/ { "cmp", TRUE, BYTE, op2(E, R), 0 }, +/*3b*/ { "cmp", TRUE, LONG, op2(E, R), 0 }, +/*3c*/ { "cmp", FALSE, BYTE, op2(Is, A), 0 }, +/*3d*/ { "cmp", FALSE, LONG, op2(Is, A), 0 }, +/*3e*/ { "", FALSE, NONE, 0, 0 }, +/*3f*/ { "aas", FALSE, NONE, 0, 0 }, + +/*40*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*41*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*42*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*43*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*44*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*45*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*46*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*47*/ { "inc", FALSE, LONG, op1(Ri), 0 }, + +/*48*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*49*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4a*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4b*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4c*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4d*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4e*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4f*/ { "dec", FALSE, LONG, op1(Ri), 0 }, + +/*50*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*51*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*52*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*53*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*54*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*55*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*56*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*57*/ { "push", FALSE, LONG, op1(Ri), 0 }, + +/*58*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*59*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5a*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5b*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5c*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5d*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5e*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5f*/ { "pop", FALSE, LONG, op1(Ri), 0 }, + +/*60*/ { "pusha", FALSE, LONG, 0, 0 }, +/*61*/ { "popa", FALSE, LONG, 0, 0 }, +/*62*/ { "bound", TRUE, LONG, op2(E, R), 0 }, +/*63*/ { "arpl", TRUE, NONE, op2(Ew,Rw), 0 }, + +/*64*/ { "", FALSE, NONE, 0, 0 }, +/*65*/ { "", FALSE, NONE, 0, 0 }, +/*66*/ { "", FALSE, NONE, 0, 0 }, +/*67*/ { "", FALSE, NONE, 0, 0 }, + +/*68*/ { "push", FALSE, LONG, op1(I), 0 }, +/*69*/ { "imul", TRUE, LONG, op3(I,E,R), 0 }, +/*6a*/ { "push", FALSE, LONG, op1(Ib), 0 }, +/*6b*/ { "imul", TRUE, LONG, op3(Ibs,E,R),0 }, +/*6c*/ { "ins", FALSE, BYTE, op2(DX, DI), 0 }, +/*6d*/ { "ins", FALSE, LONG, op2(DX, DI), 0 }, +/*6e*/ { "outs", FALSE, BYTE, op2(SI, DX), 0 }, +/*6f*/ { "outs", FALSE, LONG, op2(SI, DX), 0 }, + +/*70*/ { "jo", FALSE, NONE, op1(Db), 0 }, +/*71*/ { "jno", FALSE, NONE, op1(Db), 0 }, +/*72*/ { "jb", FALSE, NONE, op1(Db), 0 }, +/*73*/ { "jnb", FALSE, NONE, op1(Db), 0 }, +/*74*/ { "jz", FALSE, NONE, op1(Db), 0 }, +/*75*/ { "jnz", FALSE, NONE, op1(Db), 0 }, +/*76*/ { "jbe", FALSE, NONE, op1(Db), 0 }, +/*77*/ { "jnbe", FALSE, NONE, op1(Db), 0 }, + +/*78*/ { "js", FALSE, NONE, op1(Db), 0 }, +/*79*/ { "jns", FALSE, NONE, op1(Db), 0 }, +/*7a*/ { "jp", FALSE, NONE, op1(Db), 0 }, +/*7b*/ { "jnp", FALSE, NONE, op1(Db), 0 }, +/*7c*/ { "jl", FALSE, NONE, op1(Db), 0 }, +/*7d*/ { "jnl", FALSE, NONE, op1(Db), 0 }, +/*7e*/ { "jle", FALSE, NONE, op1(Db), 0 }, +/*7f*/ { "jnle", FALSE, NONE, op1(Db), 0 }, + +/*80*/ { "", TRUE, BYTE, op2(I, E), (char *)db_Grp1 }, +/*81*/ { "", TRUE, LONG, op2(I, E), (char *)db_Grp1 }, +/*82*/ { "", TRUE, BYTE, op2(Is,E), (char *)db_Grp1 }, +/*83*/ { "", TRUE, LONG, op2(Ibs,E), (char *)db_Grp1 }, +/*84*/ { "test", TRUE, BYTE, op2(R, E), 0 }, +/*85*/ { "test", TRUE, LONG, op2(R, E), 0 }, +/*86*/ { "xchg", TRUE, BYTE, op2(R, E), 0 }, +/*87*/ { "xchg", TRUE, LONG, op2(R, E), 0 }, + +/*88*/ { "mov", TRUE, BYTE, op2(R, E), 0 }, +/*89*/ { "mov", TRUE, LONG, op2(R, E), 0 }, +/*8a*/ { "mov", TRUE, BYTE, op2(E, R), 0 }, +/*8b*/ { "mov", TRUE, LONG, op2(E, R), 0 }, +/*8c*/ { "mov", TRUE, NONE, op2(S, Ew), 0 }, +/*8d*/ { "lea", TRUE, LONG, op2(E, R), 0 }, +/*8e*/ { "mov", TRUE, NONE, op2(Ew, S), 0 }, +/*8f*/ { "pop", TRUE, LONG, op1(E), 0 }, + +/*90*/ { "nop", FALSE, NONE, 0, 0 }, +/*91*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*92*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*93*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*94*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*95*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*96*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*97*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, + +/*98*/ { "cbw", FALSE, SDEP, 0, "cwde" }, /* cbw/cwde */ +/*99*/ { "cwd", FALSE, SDEP, 0, "cdq" }, /* cwd/cdq */ +/*9a*/ { "lcall", FALSE, NONE, op1(OS), 0 }, +/*9b*/ { "wait", FALSE, NONE, 0, 0 }, +/*9c*/ { "pushf", FALSE, LONG, 0, 0 }, +/*9d*/ { "popf", FALSE, LONG, 0, 0 }, +/*9e*/ { "sahf", FALSE, NONE, 0, 0 }, +/*9f*/ { "lahf", FALSE, NONE, 0, 0 }, + +/*a0*/ { "mov", FALSE, BYTE, op2(O, A), 0 }, +/*a1*/ { "mov", FALSE, LONG, op2(O, A), 0 }, +/*a2*/ { "mov", FALSE, BYTE, op2(A, O), 0 }, +/*a3*/ { "mov", FALSE, LONG, op2(A, O), 0 }, +/*a4*/ { "movs", FALSE, BYTE, op2(SI,DI), 0 }, +/*a5*/ { "movs", FALSE, LONG, op2(SI,DI), 0 }, +/*a6*/ { "cmps", FALSE, BYTE, op2(SI,DI), 0 }, +/*a7*/ { "cmps", FALSE, LONG, op2(SI,DI), 0 }, + +/*a8*/ { "test", FALSE, BYTE, op2(I, A), 0 }, +/*a9*/ { "test", FALSE, LONG, op2(I, A), 0 }, +/*aa*/ { "stos", FALSE, BYTE, op1(DI), 0 }, +/*ab*/ { "stos", FALSE, LONG, op1(DI), 0 }, +/*ac*/ { "ldos", FALSE, BYTE, op1(SI), 0 }, +/*ad*/ { "ldos", FALSE, LONG, op1(SI), 0 }, +/*ae*/ { "scas", FALSE, BYTE, op1(SI), 0 }, +/*af*/ { "scas", FALSE, LONG, op1(SI), 0 }, + +/*b0*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b1*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b2*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b3*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b4*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b5*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b6*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b7*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, + +/*b8*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*b9*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*ba*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bb*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bc*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bd*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*be*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bf*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, + +/*c0*/ { "", TRUE, BYTE, op2(Ib, E), (char *)db_Grp2 }, +/*c1*/ { "", TRUE, LONG, op2(Ib, E), (char *)db_Grp2 }, +/*c2*/ { "ret", FALSE, NONE, op1(Iw), 0 }, +/*c3*/ { "ret", FALSE, NONE, 0, 0 }, +/*c4*/ { "les", TRUE, LONG, op2(E, R), 0 }, +/*c5*/ { "lds", TRUE, LONG, op2(E, R), 0 }, +/*c6*/ { "mov", TRUE, BYTE, op2(I, E), 0 }, +/*c7*/ { "mov", TRUE, LONG, op2(I, E), 0 }, + +/*c8*/ { "enter", FALSE, NONE, op2(Ib, Iw), 0 }, +/*c9*/ { "leave", FALSE, NONE, 0, 0 }, +/*ca*/ { "lret", FALSE, NONE, op1(Iw), 0 }, +/*cb*/ { "lret", FALSE, NONE, 0, 0 }, +/*cc*/ { "int", FALSE, NONE, op1(o3), 0 }, +/*cd*/ { "int", FALSE, NONE, op1(Ib), 0 }, +/*ce*/ { "into", FALSE, NONE, 0, 0 }, +/*cf*/ { "iret", FALSE, NONE, 0, 0 }, + +/*d0*/ { "", TRUE, BYTE, op2(o1, E), (char *)db_Grp2 }, +/*d1*/ { "", TRUE, LONG, op2(o1, E), (char *)db_Grp2 }, +/*d2*/ { "", TRUE, BYTE, op2(CL, E), (char *)db_Grp2 }, +/*d3*/ { "", TRUE, LONG, op2(CL, E), (char *)db_Grp2 }, +/*d4*/ { "aam", TRUE, NONE, 0, 0 }, +/*d5*/ { "aad", TRUE, NONE, 0, 0 }, +/*d6*/ { "", FALSE, NONE, 0, 0 }, +/*d7*/ { "xlat", FALSE, BYTE, op1(BX), 0 }, + +/*d8*/ { "", TRUE, NONE, 0, (char *)db_Esc8 }, +/*d9*/ { "", TRUE, NONE, 0, (char *)db_Esc9 }, +/*da*/ { "", TRUE, NONE, 0, (char *)db_Esca }, +/*db*/ { "", TRUE, NONE, 0, (char *)db_Escb }, +/*dc*/ { "", TRUE, NONE, 0, (char *)db_Escc }, +/*dd*/ { "", TRUE, NONE, 0, (char *)db_Escd }, +/*de*/ { "", TRUE, NONE, 0, (char *)db_Esce }, +/*df*/ { "", TRUE, NONE, 0, (char *)db_Escf }, + +/*e0*/ { "loopne",FALSE, NONE, op1(Db), 0 }, +/*e1*/ { "loope", FALSE, NONE, op1(Db), 0 }, +/*e2*/ { "loop", FALSE, NONE, op1(Db), 0 }, +/*e3*/ { "jcxz", FALSE, SDEP, op1(Db), "jecxz" }, +/*e4*/ { "in", FALSE, BYTE, op2(Ib, A), 0 }, +/*e5*/ { "in", FALSE, LONG, op2(Ib, A) , 0 }, +/*e6*/ { "out", FALSE, BYTE, op2(A, Ib), 0 }, +/*e7*/ { "out", FALSE, LONG, op2(A, Ib) , 0 }, + +/*e8*/ { "call", FALSE, NONE, op1(Dl), 0 }, +/*e9*/ { "jmp", FALSE, NONE, op1(Dl), 0 }, +/*ea*/ { "ljmp", FALSE, NONE, op1(OS), 0 }, +/*eb*/ { "jmp", FALSE, NONE, op1(Db), 0 }, +/*ec*/ { "in", FALSE, BYTE, op2(DX, A), 0 }, +/*ed*/ { "in", FALSE, LONG, op2(DX, A) , 0 }, +/*ee*/ { "out", FALSE, BYTE, op2(A, DX), 0 }, +/*ef*/ { "out", FALSE, LONG, op2(A, DX) , 0 }, + +/*f0*/ { "", FALSE, NONE, 0, 0 }, +/*f1*/ { "", FALSE, NONE, 0, 0 }, +/*f2*/ { "", FALSE, NONE, 0, 0 }, +/*f3*/ { "", FALSE, NONE, 0, 0 }, +/*f4*/ { "hlt", FALSE, NONE, 0, 0 }, +/*f5*/ { "cmc", FALSE, NONE, 0, 0 }, +/*f6*/ { "", TRUE, BYTE, 0, (char *)db_Grp3 }, +/*f7*/ { "", TRUE, LONG, 0, (char *)db_Grp3 }, + +/*f8*/ { "clc", FALSE, NONE, 0, 0 }, +/*f9*/ { "stc", FALSE, NONE, 0, 0 }, +/*fa*/ { "cli", FALSE, NONE, 0, 0 }, +/*fb*/ { "sti", FALSE, NONE, 0, 0 }, +/*fc*/ { "cld", FALSE, NONE, 0, 0 }, +/*fd*/ { "std", FALSE, NONE, 0, 0 }, +/*fe*/ { "", TRUE, NONE, 0, (char *)db_Grp4 }, +/*ff*/ { "", TRUE, NONE, 0, (char *)db_Grp5 }, +}; + +struct inst db_bad_inst = + { "???", FALSE, NONE, 0, 0 } +; + +#define f_mod(byte) ((byte)>>6) +#define f_reg(byte) (((byte)>>3)&0x7) +#define f_rm(byte) ((byte)&0x7) + +#define sib_ss(byte) ((byte)>>6) +#define sib_index(byte) (((byte)>>3)&0x7) +#define sib_base(byte) ((byte)&0x7) + +struct i_addr { + int is_reg; /* if reg, reg number is in 'disp' */ + int disp; + char * base; + char * index; + int ss; +}; + +char * db_index_reg_16[8] = { + "%bx,%si", + "%bx,%di", + "%bp,%si", + "%bp,%di", + "%si", + "%di", + "%bp", + "%bx" +}; + +char * db_reg[3][8] = { + "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", + "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", + "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi" +}; + +char * db_seg_reg[8] = { + "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "", "" +}; + +/* + * lengths for size attributes + */ +int db_lengths[] = { + 1, /* BYTE */ + 2, /* WORD */ + 4, /* LONG */ + 8, /* QUAD */ + 4, /* SNGL */ + 8, /* DBLR */ + 10, /* EXTR */ +}; + +#define get_value_inc(result, loc, size, is_signed) \ + result = db_get_value((loc), (size), (is_signed)); \ + (loc) += (size); + +/* + * Read address at location and return updated location. + */ +db_addr_t +db_read_address(loc, short_addr, regmodrm, addrp) + db_addr_t loc; + int short_addr; + int regmodrm; + struct i_addr *addrp; /* out */ +{ + int mod, rm, sib, index, ss, disp; + + mod = f_mod(regmodrm); + rm = f_rm(regmodrm); + + if (mod == 3) { + addrp->is_reg = TRUE; + addrp->disp = rm; + return (loc); + } + addrp->is_reg = FALSE; + addrp->index = 0; + + if (short_addr) { + addrp->index = 0; + addrp->ss = 0; + switch (mod) { + case 0: + if (rm == 6) { + get_value_inc(disp, loc, 2, TRUE); + addrp->disp = disp; + addrp->base = 0; + } + else { + addrp->disp = 0; + addrp->base = db_index_reg_16[rm]; + } + break; + case 1: + get_value_inc(disp, loc, 1, TRUE); + addrp->disp = disp; + addrp->base = db_index_reg_16[rm]; + break; + case 2: + get_value_inc(disp, loc, 2, TRUE); + addrp->disp = disp; + addrp->base = db_index_reg_16[rm]; + break; + } + } + else { + if (mod != 3 && rm == 4) { + get_value_inc(sib, loc, 1, FALSE); + rm = sib_base(sib); + index = sib_index(sib); + if (index != 4) + addrp->index = db_reg[LONG][index]; + addrp->ss = sib_ss(sib); + } + + switch (mod) { + case 0: + if (rm == 5) { + get_value_inc(addrp->disp, loc, 4, FALSE); + addrp->base = 0; + } + else { + addrp->disp = 0; + addrp->base = db_reg[LONG][rm]; + } + break; + + case 1: + get_value_inc(disp, loc, 1, TRUE); + addrp->disp = disp; + addrp->base = db_reg[LONG][rm]; + break; + + case 2: + get_value_inc(disp, loc, 4, FALSE); + addrp->disp = disp; + addrp->base = db_reg[LONG][rm]; + break; + } + } + return (loc); +} + +void +db_print_address(seg, size, addrp) + char * seg; + int size; + struct i_addr *addrp; +{ + if (addrp->is_reg) { + db_printf("%s", db_reg[size][addrp->disp]); + return; + } + + if (seg) { + db_printf("%s:", seg); + } + + db_printsym((db_addr_t)addrp->disp, DB_STGY_ANY); + if (addrp->base != 0 || addrp->index != 0) { + db_printf("("); + if (addrp->base) + db_printf("%s", addrp->base); + if (addrp->index) + db_printf(",%s,%d", addrp->index, 1<<addrp->ss); + db_printf(")"); + } +} + +/* + * Disassemble floating-point ("escape") instruction + * and return updated location. + */ +db_addr_t +db_disasm_esc(loc, inst, short_addr, size, seg) + db_addr_t loc; + int inst; + int short_addr; + int size; + char * seg; +{ + int regmodrm; + struct finst *fp; + int mod; + struct i_addr address; + char * name; + + get_value_inc(regmodrm, loc, 1, FALSE); + fp = &db_Esc_inst[inst - 0xd8][f_reg(regmodrm)]; + mod = f_mod(regmodrm); + if (mod != 3) { + /* + * Normal address modes. + */ + loc = db_read_address(loc, short_addr, regmodrm, &address); + db_printf(fp->f_name); + switch(fp->f_size) { + case SNGL: + db_printf("s"); + break; + case DBLR: + db_printf("l"); + break; + case EXTR: + db_printf("t"); + break; + case WORD: + db_printf("s"); + break; + case LONG: + db_printf("l"); + break; + case QUAD: + db_printf("q"); + break; + default: + break; + } + db_printf("\t"); + db_print_address(seg, BYTE, &address); + } + else { + /* + * 'reg-reg' - special formats + */ + switch (fp->f_rrmode) { + case op2(ST,STI): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + db_printf("%s\t%%st,%%st(%d)",name,f_rm(regmodrm)); + break; + case op2(STI,ST): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + db_printf("%s\t%%st(%d),%%st",name, f_rm(regmodrm)); + break; + case op1(STI): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + db_printf("%s\t%%st(%d)",name, f_rm(regmodrm)); + break; + case op1(X): + db_printf("%s", ((char **)fp->f_rrname)[f_rm(regmodrm)]); + break; + case op1(XA): + db_printf("%s\t%%ax", + ((char **)fp->f_rrname)[f_rm(regmodrm)]); + break; + default: + db_printf("<bad instruction>"); + break; + } + } + + return (loc); +} + +/* + * Disassemble instruction at 'loc'. 'altfmt' specifies an + * (optional) alternate format. Return address of start of + * next instruction. + */ +db_addr_t +db_disasm(loc, altfmt) + db_addr_t loc; + boolean_t altfmt; +{ + int inst; + int size; + int short_addr; + char * seg; + struct inst * ip; + char * i_name; + int i_size; + int i_mode; + int regmodrm; + boolean_t first; + int displ; + int prefix; + int imm; + int imm2; + int len; + struct i_addr address; + + get_value_inc(inst, loc, 1, FALSE); + short_addr = FALSE; + size = LONG; + seg = 0; + + /* + * Get prefixes + */ + prefix = TRUE; + do { + switch (inst) { + case 0x66: /* data16 */ + size = WORD; + break; + case 0x67: + short_addr = TRUE; + break; + case 0x26: + seg = "%es"; + break; + case 0x36: + seg = "%ss"; + break; + case 0x2e: + seg = "%cs"; + break; + case 0x3e: + seg = "%ds"; + break; + case 0x64: + seg = "%fs"; + break; + case 0x65: + seg = "%gs"; + break; + case 0xf0: + db_printf("lock "); + break; + case 0xf2: + db_printf("repne "); + break; + case 0xf3: + db_printf("repe "); /* XXX repe VS rep */ + break; + default: + prefix = FALSE; + break; + } + if (prefix) { + get_value_inc(inst, loc, 1, FALSE); + } + } while (prefix); + + if (inst >= 0xd8 && inst <= 0xdf) { + loc = db_disasm_esc(loc, inst, short_addr, size, seg); + db_printf("\n"); + return (loc); + } + + if (inst == 0x0f) { + get_value_inc(inst, loc, 1, FALSE); + ip = db_inst_0f[inst>>4]; + if (ip == 0) { + ip = &db_bad_inst; + } + else { + ip = &ip[inst&0xf]; + } + } + else + ip = &db_inst_table[inst]; + + if (ip->i_has_modrm) { + get_value_inc(regmodrm, loc, 1, FALSE); + loc = db_read_address(loc, short_addr, regmodrm, &address); + } + + i_name = ip->i_name; + i_size = ip->i_size; + i_mode = ip->i_mode; + + if (ip->i_extra == (char *)db_Grp1 || + ip->i_extra == (char *)db_Grp2 || + ip->i_extra == (char *)db_Grp6 || + ip->i_extra == (char *)db_Grp7 || + ip->i_extra == (char *)db_Grp8) { + i_name = ((char **)ip->i_extra)[f_reg(regmodrm)]; + } + else if (ip->i_extra == (char *)db_Grp3) { + ip = (struct inst *)ip->i_extra; + ip = &ip[f_reg(regmodrm)]; + i_name = ip->i_name; + i_mode = ip->i_mode; + } + else if (ip->i_extra == (char *)db_Grp4 || + ip->i_extra == (char *)db_Grp5) { + ip = (struct inst *)ip->i_extra; + ip = &ip[f_reg(regmodrm)]; + i_name = ip->i_name; + i_mode = ip->i_mode; + i_size = ip->i_size; + } + + if (i_size == SDEP) { + if (size == WORD) + db_printf(i_name); + else + db_printf(ip->i_extra); + } + else { + db_printf(i_name); + if (i_size != NONE) { + if (i_size == BYTE) { + db_printf("b"); + size = BYTE; + } + else if (i_size == WORD) { + db_printf("w"); + size = WORD; + } + else if (size == WORD) + db_printf("w"); + else + db_printf("l"); + } + } + db_printf("\t"); + for (first = TRUE; + i_mode != 0; + i_mode >>= 8, first = FALSE) + { + if (!first) + db_printf(","); + + switch (i_mode & 0xFF) { + + case E: + db_print_address(seg, size, &address); + break; + + case Eind: + db_printf("*"); + db_print_address(seg, size, &address); + break; + + case Ew: + db_print_address(seg, WORD, &address); + break; + + case Eb: + db_print_address(seg, BYTE, &address); + break; + + case R: + db_printf("%s", db_reg[size][f_reg(regmodrm)]); + break; + + case Rw: + db_printf("%s", db_reg[WORD][f_reg(regmodrm)]); + break; + + case Ri: + db_printf("%s", db_reg[size][f_rm(inst)]); + break; + + case S: + db_printf("%s", db_seg_reg[f_reg(regmodrm)]); + break; + + case Si: + db_printf("%s", db_seg_reg[f_reg(inst)]); + break; + + case A: + db_printf("%s", db_reg[size][0]); /* acc */ + break; + + case BX: + if (seg) + db_printf("%s:", seg); + db_printf("(%s)", short_addr ? "%bx" : "%ebx"); + break; + + case CL: + db_printf("%%cl"); + break; + + case DX: + db_printf("%%dx"); + break; + + case SI: + if (seg) + db_printf("%s:", seg); + db_printf("(%s)", short_addr ? "%si" : "%esi"); + break; + + case DI: + db_printf("%%es:(%s)", short_addr ? "%di" : "%edi"); + break; + + case CR: + db_printf("%%cr%d", f_reg(regmodrm)); + break; + + case DR: + db_printf("%%dr%d", f_reg(regmodrm)); + break; + + case TR: + db_printf("%%tr%d", f_reg(regmodrm)); + break; + + case I: + len = db_lengths[size]; + get_value_inc(imm, loc, len, FALSE);/* unsigned */ + db_printf("$%#n", imm); + break; + + case Is: + len = db_lengths[size]; + get_value_inc(imm, loc, len, TRUE); /* signed */ + db_printf("$%#r", imm); + break; + + case Ib: + get_value_inc(imm, loc, 1, FALSE); /* unsigned */ + db_printf("$%#n", imm); + break; + + case Ibs: + get_value_inc(imm, loc, 1, TRUE); /* signed */ + db_printf("$%#r", imm); + break; + + case Iw: + get_value_inc(imm, loc, 2, FALSE); /* unsigned */ + db_printf("$%#n", imm); + break; + + case Il: + get_value_inc(imm, loc, 4, FALSE); + db_printf("$%#n", imm); + break; + + case O: + if (short_addr) { + get_value_inc(displ, loc, 2, TRUE); + } + else { + get_value_inc(displ, loc, 4, TRUE); + } + if (seg) + db_printf("%s:%#r",seg, displ); + else + db_printsym((db_addr_t)displ, DB_STGY_ANY); + break; + + case Db: + get_value_inc(displ, loc, 1, TRUE); + db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN); + break; + + case Dl: + get_value_inc(displ, loc, 4, TRUE); + db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN); + break; + + case o1: + db_printf("$1"); + break; + + case o3: + db_printf("$3"); + break; + + case OS: + get_value_inc(imm, loc, 4, FALSE); /* offset */ + get_value_inc(imm2, loc, 2, FALSE); /* segment */ + db_printf("$%#n,%#n", imm2, imm); + break; + } + } + + if (altfmt == 0) { + if (inst == 0xe9 || inst == 0xeb) { + /* + * GAS pads to longword boundary after unconditional jumps. + */ + loc = (loc + (4-1)) & ~(4-1); + } + } + db_printf("\n"); + return (loc); +} + diff --git a/sys/amd64/amd64/db_interface.c b/sys/amd64/amd64/db_interface.c new file mode 100644 index 000000000000..31e7849e016d --- /dev/null +++ b/sys/amd64/amd64/db_interface.c @@ -0,0 +1,255 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_interface.c,v $ + * Revision 1.1 1992/03/25 21:42:03 pace + * Initial revision + * + * Revision 2.4 91/02/05 17:11:13 mrt + * Changed to new Mach copyright + * [91/02/01 17:31:17 mrt] + * + * Revision 2.3 90/12/04 14:45:55 jsb + * Changes for merged intel/pmap.{c,h}. + * [90/12/04 11:14:41 jsb] + * + * Revision 2.2 90/10/25 14:44:43 rwd + * Added watchpoint support. + * [90/10/18 rpd] + * + * Created. + * [90/07/25 dbg] + * + * + */ + +/* + * Interface to new debugger. + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> + +#include <sys/reboot.h> +#include <vm/vm_statistics.h> +#include <vm/pmap.h> + +#include <setjmp.h> +#include <sys/systm.h> /* just for boothowto --eichin */ +int db_active = 0; + +/* + * Received keyboard interrupt sequence. + */ +kdb_kbd_trap(regs) + struct i386_saved_state *regs; +{ + if (db_active == 0 && (boothowto & RB_KDB)) { + printf("\n\nkernel: keyboard interrupt\n"); + kdb_trap(-1, 0, regs); + } +} + +/* + * kdb_trap - field a TRACE or BPT trap + */ + +static jmp_buf *db_nofault = 0; + +kdb_trap(type, code, regs) + int type, code; + register struct i386_saved_state *regs; +{ +#if 0 + if ((boothowto&RB_KDB) == 0) + return(0); +#endif + + switch (type) { + case T_BPTFLT /* T_INT3 */: /* breakpoint */ + case T_KDBTRAP /* T_WATCHPOINT */: /* watchpoint */ + case T_PRIVINFLT /* T_DEBUG */: /* single_step */ + + case -1: /* keyboard interrupt */ + break; + + default: + kdbprinttrap(type, code); + + if (db_nofault) { + jmp_buf *no_fault = db_nofault; + db_nofault = 0; + longjmp(*no_fault, 1); + } + } + + /* Should switch to kdb`s own stack here. */ + + ddb_regs = *regs; + + if ((regs->tf_cs & 0x3) == 0) { + /* + * Kernel mode - esp and ss not saved + */ + ddb_regs.tf_esp = (int)®s->tf_esp; /* kernel stack pointer */ +#if 0 + ddb_regs.ss = KERNEL_DS; +#endif + asm(" movw %%ss,%%ax; movl %%eax,%0 " + : "=g" (ddb_regs.tf_ss) + : + : "ax"); + } + + db_active++; + cnpollc(TRUE); + db_trap(type, code); + cnpollc(FALSE); + db_active--; + + regs->tf_eip = ddb_regs.tf_eip; + regs->tf_eflags = ddb_regs.tf_eflags; + regs->tf_eax = ddb_regs.tf_eax; + regs->tf_ecx = ddb_regs.tf_ecx; + regs->tf_edx = ddb_regs.tf_edx; + regs->tf_ebx = ddb_regs.tf_ebx; + if (regs->tf_cs & 0x3) { + /* + * user mode - saved esp and ss valid + */ + regs->tf_esp = ddb_regs.tf_esp; /* user stack pointer */ + regs->tf_ss = ddb_regs.tf_ss & 0xffff; /* user stack segment */ + } + regs->tf_ebp = ddb_regs.tf_ebp; + regs->tf_esi = ddb_regs.tf_esi; + regs->tf_edi = ddb_regs.tf_edi; + regs->tf_es = ddb_regs.tf_es & 0xffff; + regs->tf_cs = ddb_regs.tf_cs & 0xffff; + regs->tf_ds = ddb_regs.tf_ds & 0xffff; +#if 0 + regs->tf_fs = ddb_regs.tf_fs & 0xffff; + regs->tf_gs = ddb_regs.tf_gs & 0xffff; +#endif + + return (1); +} + +/* + * Print trap reason. + */ +kdbprinttrap(type, code) + int type, code; +{ + printf("kernel: "); + printf("type %d", type); + printf(" trap, code=%x\n", code); +} + +/* + * Read bytes from kernel address space for debugger. + */ + +extern jmp_buf db_jmpbuf; + +void +db_read_bytes(addr, size, data) + vm_offset_t addr; + register int size; + register char *data; +{ + register char *src; + + db_nofault = &db_jmpbuf; + + src = (char *)addr; + while (--size >= 0) + *data++ = *src++; + + db_nofault = 0; +} + +struct pte *pmap_pte(pmap_t, vm_offset_t); + +/* + * Write bytes to kernel address space for debugger. + */ +void +db_write_bytes(addr, size, data) + vm_offset_t addr; + register int size; + register char *data; +{ + register char *dst; + + register pt_entry_t *ptep0 = 0; + pt_entry_t oldmap0 = { 0 }; + vm_offset_t addr1; + register pt_entry_t *ptep1 = 0; + pt_entry_t oldmap1 = { 0 }; + extern char etext; + + db_nofault = &db_jmpbuf; + + if (addr >= VM_MIN_KERNEL_ADDRESS && + addr <= (vm_offset_t)&etext) + { + ptep0 = pmap_pte(kernel_pmap, addr); + oldmap0 = *ptep0; + *(int *)ptep0 |= /* INTEL_PTE_WRITE */ PG_RW; + + addr1 = i386_trunc_page(addr + size - 1); + if (i386_trunc_page(addr) != addr1) { + /* data crosses a page boundary */ + + ptep1 = pmap_pte(kernel_pmap, addr1); + oldmap1 = *ptep1; + *(int *)ptep1 |= /* INTEL_PTE_WRITE */ PG_RW; + } + tlbflush(); + } + + dst = (char *)addr; + + while (--size >= 0) + *dst++ = *data++; + + db_nofault = 0; + + if (ptep0) { + *ptep0 = oldmap0; + if (ptep1) { + *ptep1 = oldmap1; + } + tlbflush(); + } +} + +Debugger (msg) +char *msg; +{ + asm ("int $3"); +} diff --git a/sys/amd64/amd64/db_trace.c b/sys/amd64/amd64/db_trace.c new file mode 100644 index 000000000000..cbffbbc06786 --- /dev/null +++ b/sys/amd64/amd64/db_trace.c @@ -0,0 +1,292 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_trace.c,v $ + * Revision 1.1 1992/03/25 21:42:05 pace + * Initial revision + * + * Revision 2.6 91/02/05 17:11:21 mrt + * Changed to new Mach copyright + * [91/02/01 17:31:32 mrt] + * + * Revision 2.5 91/01/09 19:55:27 rpd + * Fixed stack tracing for threads without kernel stacks. + * [91/01/09 rpd] + * + * Revision 2.4 91/01/08 15:10:22 rpd + * Reorganized the pcb. + * [90/12/11 rpd] + * + * Revision 2.3 90/11/05 14:27:07 rpd + * If we can not guess the number of args to a function, use 5 vs 0. + * [90/11/02 rvb] + * + * Revision 2.2 90/08/27 21:56:20 dbg + * Import db_sym.h. + * [90/08/21 dbg] + * Fix includes. + * [90/08/08 dbg] + * Created from rvb's code for new debugger. + * [90/07/11 dbg] + * + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> + +#include <ddb/db_access.h> +#include <ddb/db_sym.h> +#include <ddb/db_variables.h> + +/* + * Machine register set. + */ +struct db_variable db_regs[] = { + "cs", (int *)&ddb_regs.tf_cs, FCN_NULL, + "ds", (int *)&ddb_regs.tf_ds, FCN_NULL, + "es", (int *)&ddb_regs.tf_es, FCN_NULL, +#if 0 + "fs", (int *)&ddb_regs.tf_fs, FCN_NULL, + "gs", (int *)&ddb_regs.tf_gs, FCN_NULL, +#endif + "ss", (int *)&ddb_regs.tf_ss, FCN_NULL, + "eax", (int *)&ddb_regs.tf_eax, FCN_NULL, + "ecx", (int *)&ddb_regs.tf_ecx, FCN_NULL, + "edx", (int *)&ddb_regs.tf_edx, FCN_NULL, + "ebx", (int *)&ddb_regs.tf_ebx, FCN_NULL, + "esp", (int *)&ddb_regs.tf_esp,FCN_NULL, + "ebp", (int *)&ddb_regs.tf_ebp, FCN_NULL, + "esi", (int *)&ddb_regs.tf_esi, FCN_NULL, + "edi", (int *)&ddb_regs.tf_edi, FCN_NULL, + "eip", (int *)&ddb_regs.tf_eip, FCN_NULL, + "efl", (int *)&ddb_regs.tf_eflags, FCN_NULL, +}; +struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); + +/* + * Stack trace. + */ +#define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS) + +struct i386_frame { + struct i386_frame *f_frame; + int f_retaddr; + int f_arg0; +}; + +#define TRAP 1 +#define INTERRUPT 2 + +db_addr_t db_trap_symbol_value = 0; +db_addr_t db_kdintr_symbol_value = 0; +boolean_t db_trace_symbols_found = FALSE; + +void +db_find_trace_symbols() +{ + db_expr_t value; + if (db_value_of_name("_trap", &value)) + db_trap_symbol_value = (db_addr_t) value; + if (db_value_of_name("_kdintr", &value)) + db_kdintr_symbol_value = (db_addr_t) value; + db_trace_symbols_found = TRUE; +} + +/* + * Figure out how many arguments were passed into the frame at "fp". + */ +int +db_numargs(fp) + struct i386_frame *fp; +{ + int *argp; + int inst; + int args; + extern char etext[]; + + argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE); + if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext) + args = 5; + else { + inst = db_get_value((int)argp, 4, FALSE); + if ((inst & 0xff) == 0x59) /* popl %ecx */ + args = 1; + else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */ + args = ((inst >> 16) & 0xff) / 4; + else + args = 5; + } + return (args); +} + +/* + * Figure out the next frame up in the call stack. + * For trap(), we print the address of the faulting instruction and + * proceed with the calling frame. We return the ip that faulted. + * If the trap was caused by jumping through a bogus pointer, then + * the next line in the backtrace will list some random function as + * being called. It should get the argument list correct, though. + * It might be possible to dig out from the next frame up the name + * of the function that faulted, but that could get hairy. + */ +void +db_nextframe(fp, ip, argp, is_trap) + struct i386_frame **fp; /* in/out */ + db_addr_t *ip; /* out */ + int *argp; /* in */ + int is_trap; /* in */ +{ + struct i386_saved_state *saved_regs; + + if (is_trap == 0) { + *ip = (db_addr_t) + db_get_value((int) &(*fp)->f_retaddr, 4, FALSE); + *fp = (struct i386_frame *) + db_get_value((int) &(*fp)->f_frame, 4, FALSE); + } else { + /* + * We know that trap() has 1 argument and we know that + * it is an (int *). + */ + saved_regs = (struct i386_saved_state *) + db_get_value((int)argp, 4, FALSE); + db_printf("--- trap (number %d) ---\n", + saved_regs->tf_trapno & 0xffff); + db_printsym(saved_regs->tf_eip, DB_STGY_XTRN); + db_printf(":\n"); + *fp = (struct i386_frame *)saved_regs->tf_ebp; + *ip = (db_addr_t)saved_regs->tf_eip; + } + +} + +void +db_stack_trace_cmd(addr, have_addr, count, modif) + db_expr_t addr; + boolean_t have_addr; + db_expr_t count; + char *modif; +{ + struct i386_frame *frame, *lastframe; + int *argp; + db_addr_t callpc; + int is_trap; + boolean_t kernel_only = TRUE; + boolean_t trace_thread = FALSE; + + if (!db_trace_symbols_found) + db_find_trace_symbols(); + + { + register char *cp = modif; + register char c; + + while ((c = *cp++) != 0) { + if (c == 't') + trace_thread = TRUE; + if (c == 'u') + kernel_only = FALSE; + } + } + + if (count == -1) + count = 65535; + + if (!have_addr) { + frame = (struct i386_frame *)ddb_regs.tf_ebp; + callpc = (db_addr_t)ddb_regs.tf_eip; + } + else if (trace_thread) { + printf ("db_trace.c: can't trace thread\n"); + } + else { + frame = (struct i386_frame *)addr; + callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE); + } + + lastframe = 0; + while (count-- && frame != 0) { + register int narg; + char * name; + db_expr_t offset; + + if (INKERNEL((int)frame) && callpc == db_trap_symbol_value) { + narg = 1; + is_trap = TRAP; + } + else + if (INKERNEL((int)frame) && callpc == db_kdintr_symbol_value) { + is_trap = INTERRUPT; + narg = 0; + } + else { + is_trap = 0; + narg = db_numargs(frame); + } + + db_find_sym_and_offset(callpc, &name, &offset); + db_printf("%s(", name); + + argp = &frame->f_arg0; + while (narg) { + db_printf("%x", db_get_value((int)argp, 4, FALSE)); + argp++; + if (--narg != 0) + db_printf(","); + } + db_printf(") at "); + db_printsym(callpc, DB_STGY_XTRN); + db_printf("\n"); + + lastframe = frame; + db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap); + + if (frame == 0) { + /* end of chain */ + break; + } + if (INKERNEL((int)frame)) { + /* staying in kernel */ + if (frame <= lastframe) { + db_printf("Bad frame pointer: 0x%x\n", frame); + break; + } + } + else if (INKERNEL((int)lastframe)) { + /* switch from user to kernel */ + if (kernel_only) + break; /* kernel stack only */ + } + else { + /* in user */ + if (frame <= lastframe) { + db_printf("Bad frame pointer: 0x%x\n", frame); + break; + } + } + } +} diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c new file mode 100644 index 000000000000..73392fabfc5e --- /dev/null +++ b/sys/amd64/amd64/fpu.c @@ -0,0 +1,564 @@ +/*- + * Copyright (c) 1990 William Jolitz. + * 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. + * + * @(#)npx.c 7.2 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Bruce Evans New npx-0.5 code + * 23 May 93 Rodney W. Grimes Return a special value of -1 from + * the probe code to keep isa_config from + * printing out the I/O address when we + * are using trap 16 handling. + * + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/isa/RCS/npx.c,v 1.2 92/01/21 14:34:27 william Exp $"; + +#include "npx.h" +#if NNPX > 0 + +#include "param.h" +#include "systm.h" +#include "conf.h" +#include "file.h" +#include "proc.h" +#include "machine/cpu.h" +#include "machine/pcb.h" +#include "machine/trap.h" +#include "ioctl.h" +#include "machine/specialreg.h" +#include "i386/isa/icu.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/isa.h" + +/* + * 387 and 287 Numeric Coprocessor Extension (NPX) Driver. + */ + +#ifdef __GNUC__ + +#define disable_intr() __asm("cli") +#define enable_intr() __asm("sti") +#define fldcw(addr) __asm("fldcw %0" : : "m" (*addr)) +#define fnclex() __asm("fnclex") +#define fninit() __asm("fninit") +#define fnsave(addr) __asm("fnsave %0" : "=m" (*addr) : "0" (*addr)) +#define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr)) +#define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr)) +#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fwait") +#define frstor(addr) __asm("frstor %0" : : "m" (*addr)) +#define fwait() __asm("fwait") +#define read_eflags() ({u_long ef; \ + __asm("pushf; popl %0" : "=a" (ef)); \ + ef; }) +#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \ + : : "n" (CR0_TS) : "ax") +#define stop_emulating() __asm("clts") +#define write_eflags(ef) __asm("pushl %0; popf" : : "a" ((u_long) ef)) + +#else /* not __GNUC__ */ + +void disable_intr __P((void)); +void enable_intr __P((void)); +void fldcw __P((caddr_t addr)); +void fnclex __P((void)); +void fninit __P((void)); +void fnsave __P((caddr_t addr)); +void fnstcw __P((caddr_t addr)); +void fnstsw __P((caddr_t addr)); +void fp_divide_by_0 __P((void)); +void frstor __P((caddr_t addr)); +void fwait __P((void)); +u_long read_eflags __P((void)); +void start_emulating __P((void)); +void stop_emulating __P((void)); +void write_eflags __P((u_long ef)); + +#endif /* __GNUC__ */ + +typedef u_char bool_t; + +extern struct gate_descriptor idt[]; + +int npxdna __P((void)); +void npxexit __P((struct proc *p)); +void npxinit __P((u_int control)); +void npxintr __P((struct intrframe frame)); +void npxsave __P((struct save87 *addr)); +static int npxattach __P((struct isa_device *dvp)); +static int npxprobe __P((struct isa_device *dvp)); +static int npxprobe1 __P((struct isa_device *dvp)); + +struct isa_driver npxdriver = { + npxprobe, npxattach, "npx", +}; + +u_int npx0mask; +struct proc *npxproc; + +static bool_t npx_ex16; +static bool_t npx_exists; +static struct gate_descriptor npx_idt_probeintr; +static int npx_intrno; +static volatile u_int npx_intrs_while_probing; +static bool_t npx_irq13; +static volatile u_int npx_traps_while_probing; + +/* + * Special interrupt handlers. Someday intr0-intr15 will be used to count + * interrupts. We'll still need a special exception 16 handler. The busy + * latch stuff in probintr() can be moved to npxprobe(). + */ +void probeintr(void); +asm +(" + .text +_probeintr: + ss + incl _npx_intrs_while_probing + pushl %eax + movb $0x20,%al /* EOI (asm in strings loses cpp features) */ + outb %al,$0xa0 /* IO_ICU2 */ + outb %al,$0x20 /* IO_ICU1 */ + movb $0,%al + outb %al,$0xf0 /* clear BUSY# latch */ + popl %eax + iret +"); + +void probetrap(void); +asm +(" + .text +_probetrap: + ss + incl _npx_traps_while_probing + fnclex + iret +"); + +/* + * Probe routine. Initialize cr0 to give correct behaviour for [f]wait + * whether the device exists or not (XXX should be elsewhere). Set flags + * to tell npxattach() what to do. Modify device struct if npx doesn't + * need to use interrupts. Return 1 if device exists. + */ +static int +npxprobe(dvp) + struct isa_device *dvp; +{ + int result; + u_long save_eflags; + u_char save_icu1_mask; + u_char save_icu2_mask; + struct gate_descriptor save_idt_npxintr; + struct gate_descriptor save_idt_npxtrap; + /* + * This routine is now just a wrapper for npxprobe1(), to install + * special npx interrupt and trap handlers, to enable npx interrupts + * and to disable other interrupts. Someday isa_configure() will + * install suitable handlers and run with interrupts enabled so we + * won't need to do so much here. + */ + npx_intrno = NRSVIDT + ffs(dvp->id_irq) - 1; + save_eflags = read_eflags(); + disable_intr(); + save_icu1_mask = inb(IO_ICU1 + 1); + save_icu2_mask = inb(IO_ICU2 + 1); + save_idt_npxintr = idt[npx_intrno]; + save_idt_npxtrap = idt[16]; + outb(IO_ICU1 + 1, ~(IRQ_SLAVE | dvp->id_irq)); + outb(IO_ICU2 + 1, ~(dvp->id_irq >> 8)); + setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL); + setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL); + npx_idt_probeintr = idt[npx_intrno]; + enable_intr(); + result = npxprobe1(dvp); + disable_intr(); + outb(IO_ICU1 + 1, save_icu1_mask); + outb(IO_ICU2 + 1, save_icu2_mask); + idt[npx_intrno] = save_idt_npxintr; + idt[16] = save_idt_npxtrap; + write_eflags(save_eflags); + return (result); +} + +static int +npxprobe1(dvp) + struct isa_device *dvp; +{ + int control; + int status; +#ifdef lint + npxintr(); +#endif + /* + * Partially reset the coprocessor, if any. Some BIOS's don't reset + * it after a warm boot. + */ + outb(0xf1, 0); /* full reset on some systems, NOP on others */ + outb(0xf0, 0); /* clear BUSY# latch */ + /* + * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT + * instructions. We must set the CR0_MP bit and use the CR0_TS + * bit to control the trap, because setting the CR0_EM bit does + * not cause WAIT instructions to trap. It's important to trap + * WAIT instructions - otherwise the "wait" variants of no-wait + * control instructions would degenerate to the "no-wait" variants + * after FP context switches but work correctly otherwise. It's + * particularly important to trap WAITs when there is no NPX - + * otherwise the "wait" variants would always degenerate. + * + * Try setting CR0_NE to get correct error reporting on 486DX's. + * Setting it should fail or do nothing on lesser processors. + */ + load_cr0(rcr0() | CR0_MP | CR0_NE); + /* + * But don't trap while we're probing. + */ + stop_emulating(); + /* + * Finish resetting the coprocessor, if any. If there is an error + * pending, then we may get a bogus IRQ13, but probeintr() will handle + * it OK. Bogus halts have never been observed, but we enabled + * IRQ13 and cleared the BUSY# latch early to handle them anyway. + */ + fninit(); + DELAY(1000); /* wait for any IRQ13 (fwait might hang) */ +#ifdef DIAGNOSTIC + if (npx_intrs_while_probing != 0) + printf("fninit caused %u bogus npx interrupt(s)\n", + npx_intrs_while_probing); + if (npx_traps_while_probing != 0) + printf("fninit caused %u bogus npx trap(s)\n", + npx_traps_while_probing); +#endif + /* + * Check for a status of mostly zero. + */ + status = 0x5a5a; + fnstsw(&status); + if ((status & 0xb8ff) == 0) { + /* + * Good, now check for a proper control word. + */ + control = 0x5a5a; + fnstcw(&control); + if ((control & 0x1f3f) == 0x033f) { + npx_exists = 1; + /* + * We have an npx, now divide by 0 to see if exception + * 16 works. + */ + control &= ~(1 << 2); /* enable divide by 0 trap */ + fldcw(&control); + npx_traps_while_probing = npx_intrs_while_probing = 0; + fp_divide_by_0(); + if (npx_traps_while_probing != 0) { + /* + * Good, exception 16 works. + */ + npx_ex16 = 1; + dvp->id_irq = 0; /* zap the interrupt */ + /* + * special return value to flag that we do not + * actually use any I/O registers + */ + return (-1); + } + if (npx_intrs_while_probing != 0) { + /* + * Bad, we are stuck with IRQ13. + */ + npx_irq13 = 1; + npx0mask = dvp->id_irq; /* npxattach too late */ + return (IO_NPXSIZE); + } + /* + * Worse, even IRQ13 is broken. Use emulator. + */ + } + } + /* + * Probe failed, but we want to get to npxattach to initialize the + * emulator and say that it has been installed. XXX handle devices + * that aren't really devices better. + */ + dvp->id_irq = 0; + return (IO_NPXSIZE); +} + +/* + * Attach routine - announce which it is, and wire into system + */ +int +npxattach(dvp) + struct isa_device *dvp; +{ + if (npx_ex16) + printf(" <Errors reported via Exception 16>"); + else if (npx_irq13) + printf(" <Errors reported via IRQ 13>"); + else if (npx_exists) + printf(" <Error reporting broken, using 387 emulator>"); + else + printf(" <387 Emulator>"); + npxinit(__INITIAL_NPXCW__); + return (1); /* XXX unused */ +} + +/* + * Initialize floating point unit. + */ +void +npxinit(control) + u_int control; +{ + struct save87 dummy; + + if (!npx_exists) + return; + /* + * fninit has the same h/w bugs as fnsave. Use the detoxified + * fnsave to throw away any junk in the fpu. fnsave initializes + * the fpu and sets npxproc = NULL as important side effects. + */ + npxsave(&dummy); + stop_emulating(); + fldcw(&control); + if (curpcb != NULL) + fnsave(&curpcb->pcb_savefpu); + start_emulating(); +} + +/* + * Free coprocessor (if we have it). + */ +void +npxexit(p) + struct proc *p; +{ + + if (p == npxproc) { + start_emulating(); + npxproc = NULL; + } +} + +/* + * Record the FPU state and reinitialize it all except for the control word. + * Then generate a SIGFPE. + * + * Reinitializing the state allows naive SIGFPE handlers to longjmp without + * doing any fixups. + * + * XXX there is currently no way to pass the full error state to signal + * handlers, and if this is a nested interrupt there is no way to pass even + * a status code! So there is no way to have a non-naive SIGFPE handler. At + * best a handler could do an fninit followed by an fldcw of a static value. + * fnclex would be of little use because it would leave junk on the FPU stack. + * Returning from the handler would be even less safe than usual because + * IRQ13 exception handling makes exceptions even less precise than usual. + */ +void +npxintr(frame) + struct intrframe frame; +{ + int code; + + if (npxproc == NULL || !npx_exists) { + /* XXX no %p in stand/printf.c. Cast to quiet gcc -Wall. */ + printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n", + (u_long) npxproc, (u_long) curproc, npx_exists); + panic("npxintr from nowhere"); + } + if (npxproc != curproc) { + printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n", + (u_long) npxproc, (u_long) curproc, npx_exists); + panic("npxintr from non-current process"); + } + /* + * Save state. This does an implied fninit. It had better not halt + * the cpu or we'll hang. + */ + outb(0xf0, 0); + fnsave(&curpcb->pcb_savefpu); + fwait(); + /* + * Restore control word (was clobbered by fnsave). + */ + fldcw(&curpcb->pcb_savefpu.sv_env.en_cw); + fwait(); + /* + * Remember the exception status word and tag word. The current + * (almost fninit'ed) fpu state is in the fpu and the exception + * state just saved will soon be junk. However, the implied fninit + * doesn't change the error pointers or register contents, and we + * preserved the control word and will copy the status and tag + * words, so the complete exception state can be recovered. + */ + curpcb->pcb_savefpu.sv_ex_sw = curpcb->pcb_savefpu.sv_env.en_sw; + curpcb->pcb_savefpu.sv_ex_tw = curpcb->pcb_savefpu.sv_env.en_tw; + + /* + * Pass exception to process. + */ + if (ISPL(frame.if_cs) == SEL_UPL) { + /* + * Interrupt is essentially a trap, so we can afford to call + * the SIGFPE handler (if any) as soon as the interrupt + * returns. + * + * XXX little or nothing is gained from this, and plenty is + * lost - the interrupt frame has to contain the trap frame + * (this is otherwise only necessary for the rescheduling trap + * in doreti, and the frame for that could easily be set up + * just before it is used). + */ + curproc->p_regs = (int *)&frame.if_es; + curpcb->pcb_flags |= FM_TRAP; /* used by sendsig */ +#ifdef notyet + /* + * Encode the appropriate code for detailed information on + * this exception. + */ + code = XXX_ENCODE(curpcb->pcb_savefpu.sv_ex_sw); +#else + code = 0; /* XXX */ +#endif + trapsignal(curproc, SIGFPE, code); + curpcb->pcb_flags &= ~FM_TRAP; + } else { + /* + * Nested interrupt. These losers occur when: + * o an IRQ13 is bogusly generated at a bogus time, e.g.: + * o immediately after an fnsave or frstor of an + * error state. + * o a couple of 386 instructions after + * "fstpl _memvar" causes a stack overflow. + * These are especially nasty when combined with a + * trace trap. + * o an IRQ13 occurs at the same time as another higher- + * priority interrupt. + * + * Treat them like a true async interrupt. + */ + psignal(npxproc, SIGFPE); + } +} + +/* + * Implement device not available (DNA) exception + * + * It would be better to switch FP context here (only). This would require + * saving the state in the proc table instead of in the pcb. + */ +int +npxdna() +{ + if (!npx_exists) + return (0); + if (npxproc != NULL) { + printf("npxdna: npxproc = %lx, curproc = %lx\n", + (u_long) npxproc, (u_long) curproc); + panic("npxdna"); + } + stop_emulating(); + /* + * Record new context early in case frstor causes an IRQ13. + */ + npxproc = curproc; + /* + * The following frstor may cause an IRQ13 when the state being + * restored has a pending error. The error will appear to have been + * triggered by the current (npx) user instruction even when that + * instruction is a no-wait instruction that should not trigger an + * error (e.g., fnclex). On at least one 486 system all of the + * no-wait instructions are broken the same as frstor, so our + * treatment does not amplify the breakage. On at least one + * 386/Cyrix 387 system, fnclex works correctly while frstor and + * fnsave are broken, so our treatment breaks fnclex if it is the + * first FPU instruction after a context switch. + */ + frstor(&curpcb->pcb_savefpu); + + return (1); +} + +/* + * Wrapper for fnsave instruction to handle h/w bugs. If there is an error + * pending, then fnsave generates a bogus IRQ13 on some systems. Force + * any IRQ13 to be handled immediately, and then ignore it. This routine is + * often called at splhigh so it must not use many system services. In + * particular, it's much easier to install a special handler than to + * guarantee that it's safe to use npxintr() and its supporting code. + */ +void +npxsave(addr) + struct save87 *addr; +{ + u_char icu1_mask; + u_char icu2_mask; + u_char old_icu1_mask; + u_char old_icu2_mask; + struct gate_descriptor save_idt_npxintr; + + disable_intr(); + old_icu1_mask = inb(IO_ICU1 + 1); + old_icu2_mask = inb(IO_ICU2 + 1); + save_idt_npxintr = idt[npx_intrno]; + outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0mask)); + outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0mask >> 8)); + idt[npx_intrno] = npx_idt_probeintr; + enable_intr(); + stop_emulating(); + fnsave(addr); + fwait(); + start_emulating(); + npxproc = NULL; + disable_intr(); + icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */ + icu2_mask = inb(IO_ICU2 + 1); + outb(IO_ICU1 + 1, + (icu1_mask & ~npx0mask) | (old_icu1_mask & npx0mask)); + outb(IO_ICU2 + 1, + (icu2_mask & ~(npx0mask >> 8)) + | (old_icu2_mask & (npx0mask >> 8))); + idt[npx_intrno] = save_idt_npxintr; + enable_intr(); /* back to usual state */ +} + +#endif /* NNPX > 0 */ diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c new file mode 100644 index 000000000000..18ec37b289b7 --- /dev/null +++ b/sys/amd64/amd64/genassym.c @@ -0,0 +1,174 @@ +/*- + * Copyright (c) 1982, 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. + * + * @(#)genassym.c 5.11 (Berkeley) 5/10/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 24 Apr 93 Bruce Evans/Dave Rivers Npx-0.5 support + * + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/genassym.c,v 1.2 92/01/21 14:22:02 william Exp $"; + +#ifndef lint +static char sccsid[] = "@(#)genassym.c 5.11 (Berkeley) 5/10/91"; +#endif /* not lint */ + +#include "sys/param.h" +#include "sys/buf.h" +#include "sys/vmmeter.h" +#include "sys/proc.h" +#include "sys/user.h" +#include "sys/mbuf.h" +#include "sys/msgbuf.h" +#include "sys/resourcevar.h" +#include "machine/cpu.h" +#include "machine/trap.h" +#include "machine/psl.h" +#include "machine/reg.h" +#include "sys/syscall.h" +#include "vm/vm_param.h" +#include "vm/vm_map.h" +#include "machine/pmap.h" + +main() +{ + struct proc *p = (struct proc *)0; + struct vmmeter *vm = (struct vmmeter *)0; + struct user *up = (struct user *)0; + struct rusage *rup = (struct rusage *)0; + struct uprof *uprof = (struct uprof *)0; + struct vmspace *vms = (struct vmspace *)0; + vm_map_t map = (vm_map_t)0; + pmap_t pmap = (pmap_t)0; + struct pcb *pcb = (struct pcb *)0; + register unsigned i; + + printf("#define\tI386_CR3PAT %d\n", I386_CR3PAT); + printf("#define\tUDOT_SZ %d\n", sizeof(struct user)); + printf("#define\tP_LINK %d\n", &p->p_link); + printf("#define\tP_RLINK %d\n", &p->p_rlink); + printf("#define\tP_VMSPACE %d\n", &p->p_vmspace); + printf("#define\tVM_PMAP %d\n", &vms->vm_pmap); + printf("#define\tP_ADDR %d\n", &p->p_addr); + printf("#define\tP_PRI %d\n", &p->p_pri); + printf("#define\tP_STAT %d\n", &p->p_stat); + printf("#define\tP_WCHAN %d\n", &p->p_wchan); + printf("#define\tP_FLAG %d\n", &p->p_flag); + printf("#define\tP_PID %d\n", &p->p_pid); + printf("#define\tSSLEEP %d\n", SSLEEP); + printf("#define\tSRUN %d\n", SRUN); + printf("#define\tV_SWTCH %d\n", &vm->v_swtch); + printf("#define\tV_TRAP %d\n", &vm->v_trap); + printf("#define\tV_SYSCALL %d\n", &vm->v_syscall); + printf("#define\tV_INTR %d\n", &vm->v_intr); + printf("#define\tV_SOFT %d\n", &vm->v_soft); + printf("#define\tV_PDMA %d\n", &vm->v_pdma); + printf("#define\tV_FAULTS %d\n", &vm->v_faults); + printf("#define\tV_PGREC %d\n", &vm->v_pgrec); + printf("#define\tV_FASTPGREC %d\n", &vm->v_fastpgrec); + printf("#define\tUPAGES %d\n", UPAGES); + printf("#define\tHIGHPAGES %d\n", HIGHPAGES); + printf("#define\tCLSIZE %d\n", CLSIZE); + printf("#define\tNBPG %d\n", NBPG); + printf("#define\tNPTEPG %d\n", NPTEPG); + printf("#define\tPGSHIFT %d\n", PGSHIFT); + printf("#define\tSYSPTSIZE %d\n", SYSPTSIZE); + printf("#define\tUSRPTSIZE %d\n", USRPTSIZE); + printf("#define\tUSRIOSIZE %d\n", USRIOSIZE); +#ifdef SYSVSHM + printf("#define\tSHMMAXPGS %d\n", SHMMAXPGS); +#endif + printf("#define\tUSRSTACK %d\n", USRSTACK); + printf("#define\tMSGBUFPTECNT %d\n", btoc(sizeof (struct msgbuf))); + printf("#define\tNMBCLUSTERS %d\n", NMBCLUSTERS); + printf("#define\tMCLBYTES %d\n", MCLBYTES); + printf("#define\tPCB_LINK %d\n", &pcb->pcb_tss.tss_link); + printf("#define\tPCB_ESP0 %d\n", &pcb->pcb_tss.tss_esp0); + printf("#define\tPCB_SS0 %d\n", &pcb->pcb_tss.tss_ss0); + printf("#define\tPCB_ESP1 %d\n", &pcb->pcb_tss.tss_esp1); + printf("#define\tPCB_SS1 %d\n", &pcb->pcb_tss.tss_ss1); + printf("#define\tPCB_ESP2 %d\n", &pcb->pcb_tss.tss_esp2); + printf("#define\tPCB_SS2 %d\n", &pcb->pcb_tss.tss_ss2); + printf("#define\tPCB_CR3 %d\n", &pcb->pcb_tss.tss_cr3); + printf("#define\tPCB_EIP %d\n", &pcb->pcb_tss.tss_eip); + printf("#define\tPCB_EFLAGS %d\n", &pcb->pcb_tss.tss_eflags); + printf("#define\tPCB_EAX %d\n", &pcb->pcb_tss.tss_eax); + printf("#define\tPCB_ECX %d\n", &pcb->pcb_tss.tss_ecx); + printf("#define\tPCB_EDX %d\n", &pcb->pcb_tss.tss_edx); + printf("#define\tPCB_EBX %d\n", &pcb->pcb_tss.tss_ebx); + printf("#define\tPCB_ESP %d\n", &pcb->pcb_tss.tss_esp); + printf("#define\tPCB_EBP %d\n", &pcb->pcb_tss.tss_ebp); + printf("#define\tPCB_ESI %d\n", &pcb->pcb_tss.tss_esi); + printf("#define\tPCB_EDI %d\n", &pcb->pcb_tss.tss_edi); + printf("#define\tPCB_ES %d\n", &pcb->pcb_tss.tss_es); + printf("#define\tPCB_CS %d\n", &pcb->pcb_tss.tss_cs); + printf("#define\tPCB_SS %d\n", &pcb->pcb_tss.tss_ss); + printf("#define\tPCB_DS %d\n", &pcb->pcb_tss.tss_ds); + printf("#define\tPCB_FS %d\n", &pcb->pcb_tss.tss_fs); + printf("#define\tPCB_GS %d\n", &pcb->pcb_tss.tss_gs); + printf("#define\tPCB_LDT %d\n", &pcb->pcb_tss.tss_ldt); + printf("#define\tPCB_IOOPT %d\n", &pcb->pcb_tss.tss_ioopt); + printf("#define\tNKMEMCLUSTERS %d\n", NKMEMCLUSTERS); + printf("#define\tU_PROF %d\n", &up->u_stats.p_prof); + printf("#define\tU_PROFSCALE %d\n", &up->u_stats.p_prof.pr_scale); + printf("#define\tPR_BASE %d\n", &uprof->pr_base); + printf("#define\tPR_SIZE %d\n", &uprof->pr_size); + printf("#define\tPR_OFF %d\n", &uprof->pr_off); + printf("#define\tPR_SCALE %d\n", &uprof->pr_scale); + printf("#define\tRU_MINFLT %d\n", &rup->ru_minflt); + printf("#define\tPCB_FLAGS %d\n", &pcb->pcb_flags); + printf("#define\tPCB_SAVEFPU %d\n", &pcb->pcb_savefpu); +#ifdef notused + printf("#define\tFP_WASUSED %d\n", FP_WASUSED); + printf("#define\tFP_NEEDSSAVE %d\n", FP_NEEDSSAVE); + printf("#define\tFP_NEEDSRESTORE %d\n", FP_NEEDSRESTORE); +#endif + printf("#define\tFP_USESEMC %d\n", FP_USESEMC); + printf("#define\tPCB_SAVEEMC %d\n", &pcb->pcb_saveemc); + printf("#define\tPCB_CMAP2 %d\n", &pcb->pcb_cmap2); + printf("#define\tPCB_SIGC %d\n", pcb->pcb_sigc); + printf("#define\tPCB_IML %d\n", &pcb->pcb_iml); + printf("#define\tPCB_ONFAULT %d\n", &pcb->pcb_onfault); + + printf("#define\tB_READ %d\n", B_READ); + printf("#define\tENOENT %d\n", ENOENT); + printf("#define\tEFAULT %d\n", EFAULT); + printf("#define\tENAMETOOLONG %d\n", ENAMETOOLONG); + exit(0); +} diff --git a/sys/amd64/amd64/locore.S b/sys/amd64/amd64/locore.S new file mode 100644 index 000000000000..d558dba24a58 --- /dev/null +++ b/sys/amd64/amd64/locore.S @@ -0,0 +1,1830 @@ +/*- + * 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. + * + * @(#)locore.s 7.3 (Berkeley) 5/13/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 5 00158 + * -------------------- ----- ---------------------- + * + * 06 Aug 92 Pace Willisson Allow VGA memory to be mapped + * 28 Nov 92 Frank MacLachlan Aligned addresses and data + * on 32bit boundaries. + * 25 Mar 93 Kevin Lahey Add syscall counter for vmstat + * 20 Apr 93 Bruce Evans New npx-0.5 code + * 25 Apr 93 Bruce Evans Support new interrupt code (intr-0.1) + */ + + +/* + * locore.s: 4BSD machine support for the Intel 386 + * Preliminary version + * Written by William F. Jolitz, 386BSD Project + */ + +#include "assym.s" +#include "machine/psl.h" +#include "machine/pte.h" + +#include "errno.h" + +#include "machine/trap.h" + +#include "machine/specialreg.h" +#include "i386/isa/debug.h" + +#define KDSEL 0x10 +#define SEL_RPL_MASK 0x0003 +#define TRAPF_CS_OFF (13 * 4) + +/* + * Note: This version greatly munged to avoid various assembler errors + * that may be fixed in newer versions of gas. Perhaps newer versions + * will have more pleasant appearance. + */ + + .set IDXSHIFT,10 + .set SYSTEM,0xFE000000 # virtual address of system start + /*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */ + .set SYSPDROFF,0x3F8 # Page dir index of System Base + +#define ALIGN_DATA .align 2 +#define ALIGN_TEXT .align 2,0x90 /* 4-byte boundaries, NOP-filled */ +#define SUPERALIGN_TEXT .align 4,0x90 /* 16-byte boundaries better for 486 */ + +/* NB: NOP now preserves registers so NOPs can be inserted anywhere */ +/* XXX: NOP and FASTER_NOP are misleadingly named */ +#ifdef BROKEN_HARDWARE_AND_OR_SOFTWARE /* XXX - rarely necessary */ +#define FASTER_NOP pushl %eax ; inb $0x84,%al ; popl %eax +#define NOP pushl %eax ; inb $0x84,%al ; inb $0x84,%al ; popl %eax +#else +#define FASTER_NOP +#define NOP +#endif + +/* + * PTmap is recursive pagemap at top of virtual address space. + * Within PTmap, the page directory can be found (third indirection). + */ + .set PDRPDROFF,0x3F7 # Page dir index of Page dir + .globl _PTmap, _PTD, _PTDpde, _Sysmap + .set _PTmap,0xFDC00000 + .set _PTD,0xFDFF7000 + .set _Sysmap,0xFDFF8000 + .set _PTDpde,0xFDFF7000+4*PDRPDROFF + +/* + * APTmap, APTD is the alternate recursive pagemap. + * It's used when modifying another process's page tables. + */ + .set APDRPDROFF,0x3FE # Page dir index of Page dir + .globl _APTmap, _APTD, _APTDpde + .set _APTmap,0xFF800000 + .set _APTD,0xFFBFE000 + .set _APTDpde,0xFDFF7000+4*APDRPDROFF + +/* + * Access to each processes kernel stack is via a region of + * per-process address space (at the beginning), immediatly above + * the user process stack. + */ + .set _kstack, USRSTACK + .globl _kstack + .set PPDROFF,0x3F6 + .set PPTEOFF,0x400-UPAGES # 0x3FE + +#define ENTRY(name) \ + .globl _/**/name; ALIGN_TEXT; _/**/name: +#define ALTENTRY(name) ENTRY(name) + +/* + * Initialization + */ + .data + .globl _cpu,_cold,_boothowto,_bootdev,_cyloffset,_atdevbase,_atdevphys +_cpu: .long 0 # are we 386, 386sx, or 486 +_cold: .long 1 # cold till we are not +_atdevbase: .long 0 # location of start of iomem in virtual +_atdevphys: .long 0 # location of device mapping ptes (phys) + + .globl _IdlePTD, _KPTphys +_IdlePTD: .long 0 +_KPTphys: .long 0 + + .space 512 +tmpstk: + .text + .globl start +start: movw $0x1234,%ax + movw %ax,0x472 # warm boot + jmp 1f + .space 0x500 # skip over warm boot shit + + /* + * pass parameters on stack (howto, bootdev, unit, cyloffset) + * note: (%esp) is return address of boot + * ( if we want to hold onto /boot, it's physical %esp up to _end) + */ + + 1: movl 4(%esp),%eax + movl %eax,_boothowto-SYSTEM + movl 8(%esp),%eax + movl %eax,_bootdev-SYSTEM + movl 12(%esp),%eax + movl %eax, _cyloffset-SYSTEM + + /* + * Finished with old stack; load new %esp now instead of later so + * we can trace this code without having to worry about the trace + * trap clobbering the memory test or the zeroing of the bss+bootstrap + * page tables. + * + * XXX - wdboot clears the bss after testing that this is safe. + * This is too wasteful - memory below 640K is scarce. The boot + * program should check: + * text+data <= &stack_variable - more_space_for_stack + * text+data+bss+pad+space_for_page_tables <= end_of_memory + * Oops, the gdt is in the carcass of the boot program so clearing + * the rest of memory is still not possible. + */ + movl $ tmpstk-SYSTEM,%esp # bootstrap stack end location + +#ifdef garbage + /* count up memory */ + + xorl %eax,%eax # start with base memory at 0x0 + #movl $ 0xA0000/NBPG,%ecx # look every 4K up to 640K + movl $ 0xA0,%ecx # look every 4K up to 640K +1: movl (%eax),%ebx # save location to check + movl $0xa55a5aa5,(%eax) # write test pattern + /* flush stupid cache here! (with bcopy (0,0,512*1024) ) */ + cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover + jne 2f + movl %ebx,(%eax) # restore memory + addl $ NBPG,%eax + loop 1b +2: shrl $12,%eax + movl %eax,_Maxmem-SYSTEM + + movl $0x100000,%eax # next, talley remaining memory + #movl $((0xFFF000-0x100000)/NBPG),%ecx + movl $(0xFFF-0x100),%ecx +1: movl (%eax),%ebx # save location to check + movl $0xa55a5aa5,(%eax) # write test pattern + cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover + jne 2f + movl %ebx,(%eax) # restore memory + addl $ NBPG,%eax + loop 1b +2: shrl $12,%eax + movl %eax,_Maxmem-SYSTEM +#endif + +/* find end of kernel image */ + movl $_end-SYSTEM,%ecx + addl $ NBPG-1,%ecx + andl $~(NBPG-1),%ecx + movl %ecx,%esi + +/* clear bss and memory for bootstrap pagetables. */ + movl $_edata-SYSTEM,%edi + subl %edi,%ecx + addl $(UPAGES+5)*NBPG,%ecx +/* + * Virtual address space of kernel: + * + * text | data | bss | page dir | proc0 kernel stack | usr stk map | Sysmap + * 0 1 2 3 4 + */ + xorl %eax,%eax # pattern + cld + rep + stosb + + movl %esi,_IdlePTD-SYSTEM /*physical address of Idle Address space */ + +#define fillkpt \ +1: movl %eax,(%ebx) ; \ + addl $ NBPG,%eax ; /* increment physical address */ \ + addl $4,%ebx ; /* next pte */ \ + loop 1b ; + +/* + * Map Kernel + * N.B. don't bother with making kernel text RO, as 386 + * ignores R/W AND U/S bits on kernel access (only v works) ! + * + * First step - build page tables + */ + movl %esi,%ecx # this much memory, + shrl $ PGSHIFT,%ecx # for this many pte s + addl $ UPAGES+4,%ecx # including our early context + movl $0xa0,%ecx # XXX - cover debugger pages + movl $PG_V|PG_KW,%eax # having these bits set, + lea (4*NBPG)(%esi),%ebx # physical address of KPT in proc 0, + movl %ebx,_KPTphys-SYSTEM # in the kernel page table, + fillkpt + +/* map I/O memory map */ + + movl $0x100-0xa0,%ecx # for this many pte s, + movl $(0xa0000|PG_V|PG_UW),%eax # having these bits set,(perhaps URW?) XXX 06 Aug 92 + movl %ebx,_atdevphys-SYSTEM # remember phys addr of ptes + fillkpt + + /* map proc 0's kernel stack into user page table page */ + + movl $ UPAGES,%ecx # for this many pte s, + lea (1*NBPG)(%esi),%eax # physical address in proc 0 + lea (SYSTEM)(%eax),%edx + movl %edx,_proc0paddr-SYSTEM # remember VA for 0th process init + orl $PG_V|PG_KW,%eax # having these bits set, + lea (3*NBPG)(%esi),%ebx # physical address of stack pt in proc 0 + addl $(PPTEOFF*4),%ebx + fillkpt + +/* + * Construct a page table directory + * (of page directory elements - pde's) + */ + /* install a pde for temporary double map of bottom of VA */ + lea (4*NBPG)(%esi),%eax # physical address of kernel page table + orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92 + movl %eax,(%esi) # which is where temp maps! + + /* kernel pde's */ + movl $ 3,%ecx # for this many pde s, + lea (SYSPDROFF*4)(%esi), %ebx # offset of pde for kernel + fillkpt + + /* install a pde recursively mapping page directory as a page table! */ + movl %esi,%eax # phys address of ptd in proc 0 + orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92 + movl %eax, PDRPDROFF*4(%esi) # which is where PTmap maps! + + /* install a pde to map kernel stack for proc 0 */ + lea (3*NBPG)(%esi),%eax # physical address of pt in proc 0 + orl $PG_V|PG_KW,%eax # pde entry is valid + movl %eax,PPDROFF*4(%esi) # which is where kernel stack maps! + + /* copy and convert stuff from old gdt and idt for debugger */ + + cmpl $0x0375c339,0x96104 # XXX - debugger signature + jne 1f + movb $1,_bdb_exists-SYSTEM +1: + pushal + subl $2*6,%esp + + sgdt (%esp) + movl 2(%esp),%esi # base address of current gdt + movl $_gdt-SYSTEM,%edi + movl %edi,2(%esp) + movl $8*18/4,%ecx + rep # copy gdt + movsl + movl $_gdt-SYSTEM,-8+2(%edi) # adjust gdt self-ptr + movb $0x92,-8+5(%edi) + + sidt 6(%esp) + movl 6+2(%esp),%esi # base address of current idt + movl 8+4(%esi),%eax # convert dbg descriptor to ... + movw 8(%esi),%ax + movl %eax,bdb_dbg_ljmp+1-SYSTEM # ... immediate offset ... + movl 8+2(%esi),%eax + movw %ax,bdb_dbg_ljmp+5-SYSTEM # ... and selector for ljmp + movl 24+4(%esi),%eax # same for bpt descriptor + movw 24(%esi),%ax + movl %eax,bdb_bpt_ljmp+1-SYSTEM + movl 24+2(%esi),%eax + movw %ax,bdb_bpt_ljmp+5-SYSTEM + + movl $_idt-SYSTEM,%edi + movl %edi,6+2(%esp) + movl $8*4/4,%ecx + rep # copy idt + movsl + + lgdt (%esp) + lidt 6(%esp) + + addl $2*6,%esp + popal + + /* load base of page directory, and enable mapping */ + movl %esi,%eax # phys address of ptd in proc 0 + orl $ I386_CR3PAT,%eax + movl %eax,%cr3 # load ptd addr into mmu + movl %cr0,%eax # get control word +#ifdef USE_486_WRITE_PROTECT + orl $CR0_PE|CR0_PG|CR0_WP,%eax # and let s page! +#else + orl $CR0_PE|CR0_PG,%eax # and let s page! +#endif + movl %eax,%cr0 # NOW! + + pushl $begin # jump to high mem! + ret + +begin: /* now running relocated at SYSTEM where the system is linked to run */ + + .globl _Crtat + movl _Crtat,%eax + subl $0xfe0a0000,%eax + movl _atdevphys,%edx # get pte PA + subl _KPTphys,%edx # remove base of ptes, now have phys offset + shll $ PGSHIFT-2,%edx # corresponding to virt offset + addl $ SYSTEM,%edx # add virtual base + movl %edx, _atdevbase + addl %eax,%edx + movl %edx,_Crtat + + /* set up bootstrap stack */ + movl $ _kstack+UPAGES*NBPG-4*12,%esp # bootstrap stack end location + xorl %eax,%eax # mark end of frames + movl %eax,%ebp + movl _proc0paddr, %eax + movl %esi, PCB_CR3(%eax) + + lea 7*NBPG(%esi),%esi # skip past stack. + pushl %esi + + /* relocate debugger gdt entries */ + + movl $_gdt+8*9,%eax # adjust slots 9-17 + movl $9,%ecx +reloc_gdt: + movb $0xfe,7(%eax) # top byte of base addresses, was 0, + addl $8,%eax # now SYSTEM>>24 + loop reloc_gdt + + cmpl $0,_bdb_exists + je 1f + int $3 +1: + + call _init386 # wire 386 chip for unix operation + + movl $0,_PTD + call _main + popl %esi + + .globl __ucodesel,__udatasel + movl __ucodesel,%eax + movl __udatasel,%ecx + # build outer stack frame + pushl %ecx # user ss + pushl $ USRSTACK # user esp + pushl %eax # user cs + pushl $0 # user ip + movl %cx,%ds + movl %cx,%es + movl %ax,%fs # double map cs to fs + movl %cx,%gs # and ds to gs + lret # goto user! + + pushl $lretmsg1 /* "should never get here!" */ + call _panic +lretmsg1: + .asciz "lret: toinit\n" + + + .set exec,59 + .set exit,1 + +#define LCALL(x,y) .byte 0x9a ; .long y; .word x +/* + * Icode is copied out to process 1 to exec /etc/init. + * If the exec fails, process 1 exits. + */ +ENTRY(icode) + # pushl $argv-_icode # gas fucks up again + movl $argv,%eax + subl $_icode,%eax + pushl %eax + + # pushl $init-_icode + movl $init,%eax + subl $_icode,%eax + pushl %eax + pushl %eax # dummy out rta + + movl %esp,%ebp + movl $exec,%eax + LCALL(0x7,0x0) + pushl %eax + movl $exit,%eax + pushl %eax # dummy out rta + LCALL(0x7,0x0) + +init: + .asciz "/sbin/init" + ALIGN_DATA +argv: + .long init+6-_icode # argv[0] = "init" ("/sbin/init" + 6) + .long eicode-_icode # argv[1] follows icode after copyout + .long 0 +eicode: + + .globl _szicode +_szicode: + .long _szicode-_icode + +ENTRY(sigcode) + call 12(%esp) + lea 28(%esp),%eax # scp (the call may have clobbered the + # copy at 8(%esp)) + # XXX - use genassym + pushl %eax + pushl %eax # junk to fake return address + movl $103,%eax # sigreturn() + LCALL(0x7,0) # enter kernel with args on stack + hlt # never gets here + + .globl _szsigcode +_szsigcode: + .long _szsigcode-_sigcode + + /* + * Support routines for GCC + */ +ENTRY(__udivsi3) + movl 4(%esp),%eax + xorl %edx,%edx + divl 8(%esp) + ret + +ENTRY(__divsi3) + movl 4(%esp),%eax + cltd + idivl 8(%esp) + ret + + /* + * I/O bus instructions via C + */ +ENTRY(inb) + movl 4(%esp),%edx + subl %eax,%eax # clr eax + NOP + inb %dx,%al + ret + + +ENTRY(inw) + movl 4(%esp),%edx + subl %eax,%eax # clr eax + NOP + inw %dx,%ax + ret + + +ENTRY(rtcin) + movl 4(%esp),%eax + outb %al,$0x70 + subl %eax,%eax # clr eax + inb $0x71,%al + ret + +ENTRY(outb) + movl 4(%esp),%edx + NOP + movl 8(%esp),%eax + outb %al,%dx + NOP + ret + +ENTRY(outw) + movl 4(%esp),%edx + NOP + movl 8(%esp),%eax + outw %ax,%dx + NOP + ret + + /* + * void bzero(void *base, u_int cnt) + */ + +ENTRY(bzero) + pushl %edi + movl 8(%esp),%edi + movl 12(%esp),%ecx + xorl %eax,%eax + shrl $2,%ecx + cld + rep + stosl + movl 12(%esp),%ecx + andl $3,%ecx + rep + stosb + popl %edi + ret + + /* + * fillw (pat,base,cnt) + */ + +ENTRY(fillw) + pushl %edi + movl 8(%esp),%eax + movl 12(%esp),%edi + movl 16(%esp),%ecx + cld + rep + stosw + popl %edi + ret + +ENTRY(bcopyb) + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + cmpl %esi,%edi /* potentially overlapping? */ + jnb 1f + cld /* nope, copy forwards */ + rep + movsb + popl %edi + popl %esi + ret + + ALIGN_TEXT +1: + addl %ecx,%edi /* copy backwards. */ + addl %ecx,%esi + std + decl %edi + decl %esi + rep + movsb + popl %edi + popl %esi + cld + ret + +ENTRY(bcopyw) + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + cmpl %esi,%edi /* potentially overlapping? */ + jnb 1f + cld /* nope, copy forwards */ + shrl $1,%ecx /* copy by 16-bit words */ + rep + movsw + adc %ecx,%ecx /* any bytes left? */ + rep + movsb + popl %edi + popl %esi + ret + + ALIGN_TEXT +1: + addl %ecx,%edi /* copy backwards */ + addl %ecx,%esi + std + andl $1,%ecx /* any fractional bytes? */ + decl %edi + decl %esi + rep + movsb + movl 20(%esp),%ecx /* copy remainder by 16-bit words */ + shrl $1,%ecx + decl %esi + decl %edi + rep + movsw + popl %edi + popl %esi + cld + ret + +ENTRY(bcopyx) + movl 16(%esp),%eax + cmpl $2,%eax + je _bcopyw + cmpl $4,%eax + jne _bcopyb + /* + * Fall through to bcopy. ENTRY() provides harmless fill bytes. + */ + + /* + * (ov)bcopy (src,dst,cnt) + * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800 + * Changed by bde to not bother returning %eax = 0. + */ + +ENTRY(ovbcopy) +ENTRY(bcopy) + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + cmpl %esi,%edi /* potentially overlapping? */ + jnb 1f + cld /* nope, copy forwards */ + shrl $2,%ecx /* copy by 32-bit words */ + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx /* any bytes left? */ + rep + movsb + popl %edi + popl %esi + ret + + ALIGN_TEXT +1: + addl %ecx,%edi /* copy backwards */ + addl %ecx,%esi + std + andl $3,%ecx /* any fractional bytes? */ + decl %edi + decl %esi + rep + movsb + movl 20(%esp),%ecx /* copy remainder by 32-bit words */ + shrl $2,%ecx + subl $3,%esi + subl $3,%edi + rep + movsl + popl %edi + popl %esi + cld + ret + +#ifdef notdef +ENTRY(copyout) + movl _curpcb, %eax + movl $cpyflt, PCB_ONFAULT(%eax) # in case we page/protection violate + pushl %esi + pushl %edi + pushl %ebx + movl 16(%esp), %esi + movl 20(%esp), %edi + movl 24(%esp), %ebx + + /* first, check to see if "write fault" */ +1: movl %edi, %eax +#ifdef notyet + shrl $IDXSHIFT, %eax /* fetch pte associated with address */ + andb $0xfc, %al + movl _PTmap(%eax), %eax + + andb $7, %al /* if we are the one case that won't trap... */ + cmpb $5, %al + jne 2f + /* ... then simulate the trap! */ + pushl %edi + call _trapwrite /* trapwrite(addr) */ + popl %edx + + cmpl $0, %eax /* if not ok, return */ + jne cpyflt + /* otherwise, continue with reference */ +2: + movl %edi, %eax /* calculate remainder this pass */ + andl $0xfffff000, %eax + movl $NBPG, %ecx + subl %eax, %ecx + cmpl %ecx, %ebx + jle 3f + movl %ebx, %ecx +3: subl %ecx, %ebx + movl %ecx, %edx +#else + movl %ebx, %ecx + movl %ebx, %edx +#endif + + shrl $2,%ecx /* movem */ + cld + rep + movsl + movl %edx, %ecx /* don't depend on ecx here! */ + andl $3, %ecx + rep + movsb + +#ifdef notyet + cmpl $0, %ebx + jl 1b +#endif + + popl %ebx + popl %edi + popl %esi + xorl %eax,%eax + movl _curpcb,%edx + movl %eax,PCB_ONFAULT(%edx) + ret + +ENTRY(copyin) + movl _curpcb,%eax + movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate + pushl %esi + pushl %edi + pushl %ebx # XXX - not used, but affects stack offsets + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + shrl $2,%ecx + cld + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx + rep + movsb + popl %ebx + popl %edi + popl %esi + xorl %eax,%eax + movl _curpcb,%edx + movl %eax,PCB_ONFAULT(%edx) + ret + + ALIGN_TEXT +cpyflt: + popl %ebx + popl %edi + popl %esi + movl _curpcb,%edx + movl $0,PCB_ONFAULT(%edx) + movl $ EFAULT,%eax + ret +#else +ENTRY(copyout) + movl _curpcb,%eax + movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + shrl $2,%ecx + cld + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx + rep + movsb + popl %edi + popl %esi + xorl %eax,%eax + movl _curpcb,%edx + movl %eax,PCB_ONFAULT(%edx) + ret + +ENTRY(copyin) + movl _curpcb,%eax + movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + shrl $2,%ecx + cld + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx + rep + movsb + popl %edi + popl %esi + xorl %eax,%eax + movl _curpcb,%edx + movl %eax,PCB_ONFAULT(%edx) + ret + + ALIGN_TEXT +cpyflt: popl %edi + popl %esi + movl _curpcb,%edx + movl $0,PCB_ONFAULT(%edx) + movl $ EFAULT,%eax + ret + +#endif + + # insb(port,addr,cnt) +ENTRY(insb) + pushl %edi + movw 8(%esp),%dx + movl 12(%esp),%edi + movl 16(%esp),%ecx + cld + NOP + rep + insb + NOP + movl %edi,%eax + popl %edi + ret + + # insw(port,addr,cnt) +ENTRY(insw) + pushl %edi + movw 8(%esp),%dx + movl 12(%esp),%edi + movl 16(%esp),%ecx + cld + NOP + .byte 0x66,0xf2,0x6d # rep insw + NOP + movl %edi,%eax + popl %edi + ret + + # outsw(port,addr,cnt) +ENTRY(outsw) + pushl %esi + movw 8(%esp),%dx + movl 12(%esp),%esi + movl 16(%esp),%ecx + cld + NOP + .byte 0x66,0xf2,0x6f # rep outsw + NOP + movl %esi,%eax + popl %esi + ret + + # outsb(port,addr,cnt) +ENTRY(outsb) + pushl %esi + movw 8(%esp),%dx + movl 12(%esp),%esi + movl 16(%esp),%ecx + cld + NOP + rep + outsb + NOP + movl %esi,%eax + popl %esi + ret + + /* + * void lgdt(struct region_descriptor *rdp); + */ +ENTRY(lgdt) + /* reload the descriptor table */ + movl 4(%esp),%eax + lgdt (%eax) + /* flush the prefetch q */ + jmp 1f + nop +1: + /* reload "stale" selectors */ + movl $KDSEL,%eax + movl %ax,%ds + movl %ax,%es + movl %ax,%ss + + /* reload code selector by turning return into intersegmental return */ + movl (%esp),%eax + pushl %eax + # movl $KCSEL,4(%esp) + movl $8,4(%esp) + lret + + /* + * void lidt(struct region_descriptor *rdp); + */ +ENTRY(lidt) + movl 4(%esp),%eax + lidt (%eax) + ret + + /* + * void lldt(u_short sel) + */ +ENTRY(lldt) + lldt 4(%esp) + ret + + /* + * void ltr(u_short sel) + */ +ENTRY(ltr) + ltr 4(%esp) + ret + + /* + * void lcr3(caddr_t cr3) + */ + ALIGN_TEXT +ENTRY(load_cr3) +ALTENTRY(lcr3) + movl 4(%esp),%eax + orl $ I386_CR3PAT,%eax + movl %eax,%cr3 + ret + + # tlbflush() +ENTRY(tlbflush) + movl %cr3,%eax + orl $ I386_CR3PAT,%eax + movl %eax,%cr3 + ret + + # lcr0(cr0) +ENTRY(lcr0) +ALTENTRY(load_cr0) + movl 4(%esp),%eax + movl %eax,%cr0 + ret + + # rcr0() +ENTRY(rcr0) + movl %cr0,%eax + ret + + # rcr2() +ENTRY(rcr2) + movl %cr2,%eax + ret + + # rcr3() +ENTRY(_cr3) +ALTENTRY(rcr3) + movl %cr3,%eax + ret + + # ssdtosd(*ssdp,*sdp) +ENTRY(ssdtosd) + pushl %ebx + movl 8(%esp),%ecx + movl 8(%ecx),%ebx + shll $16,%ebx + movl (%ecx),%edx + roll $16,%edx + movb %dh,%bl + movb %dl,%bh + rorl $8,%ebx + movl 4(%ecx),%eax + movw %ax,%dx + andl $0xf0000,%eax + orl %eax,%ebx + movl 12(%esp),%ecx + movl %edx,(%ecx) + movl %ebx,4(%ecx) + popl %ebx + ret + +/* + * {fu,su},{byte,word} + */ +ALTENTRY(fuiword) +ENTRY(fuword) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) + movl 4(%esp),%edx + .byte 0x65 # use gs + movl (%edx),%eax + movl $0,PCB_ONFAULT(%ecx) + ret + +ENTRY(fusword) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + .byte 0x65 # use gs + movzwl (%edx),%eax + movl $0,PCB_ONFAULT(%ecx) + ret + +ALTENTRY(fuibyte) +ENTRY(fubyte) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + .byte 0x65 # use gs + movzbl (%edx),%eax + movl $0,PCB_ONFAULT(%ecx) + ret + + ALIGN_TEXT +fusufault: + movl _curpcb,%ecx + xorl %eax,%eax + movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate + decl %eax + ret + +ALTENTRY(suiword) +ENTRY(suword) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + movl 8(%esp),%eax + +#ifdef notdef + shrl $IDXSHIFT, %edx /* fetch pte associated with address */ + andb $0xfc, %dl + movl _PTmap(%edx), %edx + + andb $7, %dl /* if we are the one case that won't trap... */ + cmpb $5 , %edx + jne 1f + /* ... then simulate the trap! */ + pushl %edi + call _trapwrite /* trapwrite(addr) */ + popl %edx + cmpl $0, %eax /* if not ok, return */ + jne fusufault + movl 8(%esp),%eax /* otherwise, continue with reference */ +1: + movl 4(%esp),%edx +#endif + .byte 0x65 # use gs + movl %eax,(%edx) + xorl %eax,%eax + movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate + ret + +ENTRY(susword) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + movl 8(%esp),%eax +#ifdef notdef +shrl $IDXSHIFT, %edx /* calculate pte address */ +andb $0xfc, %dl +movl _PTmap(%edx), %edx +andb $7, %edx /* if we are the one case that won't trap... */ +cmpb $5 , %edx +jne 1f +/* ..., then simulate the trap! */ + pushl %edi + call _trapwrite /* trapwrite(addr) */ + popl %edx +movl _curpcb, %ecx # restore trashed registers +cmpl $0, %eax /* if not ok, return */ +jne fusufault +movl 8(%esp),%eax +1: movl 4(%esp),%edx +#endif + .byte 0x65 # use gs + movw %ax,(%edx) + xorl %eax,%eax + movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate + ret + +ALTENTRY(suibyte) +ENTRY(subyte) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + movl 8(%esp),%eax +#ifdef notdef +shrl $IDXSHIFT, %edx /* calculate pte address */ +andb $0xfc, %dl +movl _PTmap(%edx), %edx +andb $7, %edx /* if we are the one case that won't trap... */ +cmpb $5 , %edx +jne 1f +/* ..., then simulate the trap! */ + pushl %edi + call _trapwrite /* trapwrite(addr) */ + popl %edx +movl _curpcb, %ecx # restore trashed registers +cmpl $0, %eax /* if not ok, return */ +jne fusufault +movl 8(%esp),%eax +1: movl 4(%esp),%edx +#endif + .byte 0x65 # use gs + movb %eax,(%edx) + xorl %eax,%eax + movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate + ret + +ENTRY(setjmp) + movl 4(%esp),%eax + movl %ebx, (%eax) # save ebx + movl %esp, 4(%eax) # save esp + movl %ebp, 8(%eax) # save ebp + movl %esi,12(%eax) # save esi + movl %edi,16(%eax) # save edi + movl (%esp),%edx # get rta + movl %edx,20(%eax) # save eip + xorl %eax,%eax # return (0); + ret + +ENTRY(longjmp) + movl 4(%esp),%eax + movl (%eax),%ebx # restore ebx + movl 4(%eax),%esp # restore esp + movl 8(%eax),%ebp # restore ebp + movl 12(%eax),%esi # restore esi + movl 16(%eax),%edi # restore edi + movl 20(%eax),%edx # get rta + movl %edx,(%esp) # put in return frame + xorl %eax,%eax # return (1); + incl %eax + ret +/* + * The following primitives manipulate the run queues. + * _whichqs tells which of the 32 queues _qs + * have processes in them. Setrq 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_pri, divided by 4 + * actually to shrink the 0-127 range of priorities into the 32 available + * queues. + */ + + .globl _whichqs,_qs,_cnt,_panic + .comm _noproc,4 + .comm _runrun,4 + +/* + * Setrq(p) + * + * Call should be made at spl6(), and p->p_stat should be SRUN + */ +ENTRY(setrq) + movl 4(%esp),%eax + cmpl $0,P_RLINK(%eax) # should not be on q already + je set1 + pushl $set2 + call _panic +set1: + movzbl P_PRI(%eax),%edx + shrl $2,%edx + btsl %edx,_whichqs # set q full bit + shll $3,%edx + addl $_qs,%edx # locate q hdr + movl %edx,P_LINK(%eax) # link process on tail of q + movl P_RLINK(%edx),%ecx + movl %ecx,P_RLINK(%eax) + movl %eax,P_RLINK(%edx) + movl %eax,P_LINK(%ecx) + ret + +set2: .asciz "setrq" + +/* + * Remrq(p) + * + * Call should be made at spl6(). + */ +ENTRY(remrq) + movl 4(%esp),%eax + movzbl P_PRI(%eax),%edx + shrl $2,%edx + btrl %edx,_whichqs # clear full bit, panic if clear already + jb rem1 + pushl $rem3 + call _panic +rem1: + pushl %edx + movl P_LINK(%eax),%ecx # unlink process + movl P_RLINK(%eax),%edx + movl %edx,P_RLINK(%ecx) + movl P_RLINK(%eax),%ecx + movl P_LINK(%eax),%edx + movl %edx,P_LINK(%ecx) + popl %edx + movl $_qs,%ecx + shll $3,%edx + addl %edx,%ecx + cmpl P_LINK(%ecx),%ecx # q still has something? + je rem2 + shrl $3,%edx # yes, set bit as still full + btsl %edx,_whichqs +rem2: + movl $0,P_RLINK(%eax) # zap reverse link to indicate off list + ret + +rem3: .asciz "remrq" +sw0: .asciz "swtch" + +/* + * When no processes are on the runq, Swtch branches to idle + * to wait for something to come ready. + */ + .globl Idle + ALIGN_TEXT +Idle: +sti_for_idle: + sti + SHOW_STI + ALIGN_TEXT +idle: + call _spl0 + cmpl $0,_whichqs + jne sw1 + hlt # wait for interrupt + jmp idle + + SUPERALIGN_TEXT /* so profiling doesn't lump Idle with swtch().. */ +badsw: + pushl $sw0 + call _panic + /*NOTREACHED*/ + +/* + * Swtch() + */ +ENTRY(swtch) + + incl _cnt+V_SWTCH + + /* switch to new process. first, save context as needed */ + + movl _curproc,%ecx + + /* if no process to save, don't bother */ + testl %ecx,%ecx + je sw1 + + movl P_ADDR(%ecx),%ecx + + movl (%esp),%eax # Hardware registers + movl %eax, PCB_EIP(%ecx) + movl %ebx, PCB_EBX(%ecx) + movl %esp, PCB_ESP(%ecx) + movl %ebp, PCB_EBP(%ecx) + movl %esi, PCB_ESI(%ecx) + movl %edi, PCB_EDI(%ecx) + +#ifdef NPX + /* have we used fp, and need a save? */ + mov _curproc,%eax + cmp %eax,_npxproc + jne 1f + pushl %ecx /* h/w bugs make saving complicated */ + leal PCB_SAVEFPU(%ecx),%eax + pushl %eax + call _npxsave /* do it in a big C function */ + popl %eax + popl %ecx +1: +#endif + + movl _CMAP2,%eax # save temporary map PTE + movl %eax,PCB_CMAP2(%ecx) # in our context + movl $0,_curproc # out of process + + # movw _cpl, %ax + # movw %ax, PCB_IML(%ecx) # save ipl + + /* save is done, now choose a new process or idle */ +sw1: + cli + SHOW_CLI + movl _whichqs,%edi +2: + # XXX - bsf is sloow + bsfl %edi,%eax # find a full q + je sti_for_idle # if none, idle + # XX update whichqs? +swfnd: + btrl %eax,%edi # clear q full status + jnb 2b # if it was clear, look for another + movl %eax,%ebx # save which one we are using + + shll $3,%eax + addl $_qs,%eax # select q + movl %eax,%esi + +#ifdef DIAGNOSTIC + cmpl P_LINK(%eax),%eax # linked to self? (e.g. not on list) + je badsw # not possible +#endif + + movl P_LINK(%eax),%ecx # unlink from front of process q + movl P_LINK(%ecx),%edx + movl %edx,P_LINK(%eax) + movl P_RLINK(%ecx),%eax + movl %eax,P_RLINK(%edx) + + cmpl P_LINK(%ecx),%esi # q empty + je 3f + btsl %ebx,%edi # nope, set to indicate full +3: + movl %edi,_whichqs # update q status + + movl $0,%eax + movl %eax,_want_resched + +#ifdef DIAGNOSTIC + cmpl %eax,P_WCHAN(%ecx) + jne badsw + cmpb $ SRUN,P_STAT(%ecx) + jne badsw +#endif + + movl %eax,P_RLINK(%ecx) /* isolate process to run */ + movl P_ADDR(%ecx),%edx + movl PCB_CR3(%edx),%ebx + + /* switch address space */ + movl %ebx,%cr3 + + /* restore context */ + movl PCB_EBX(%edx), %ebx + movl PCB_ESP(%edx), %esp + movl PCB_EBP(%edx), %ebp + movl PCB_ESI(%edx), %esi + movl PCB_EDI(%edx), %edi + movl PCB_EIP(%edx), %eax + movl %eax, (%esp) + + movl PCB_CMAP2(%edx),%eax # get temporary map + movl %eax,_CMAP2 # reload temporary map PTE + + movl %ecx,_curproc # into next process + movl %edx,_curpcb + + pushl %edx # save p to return +/* + * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1? + * I think restoring the cpl is unnecessary, but we must turn off the cli + * now that spl*() don't do it as a side affect. + */ + pushl PCB_IML(%edx) + sti + SHOW_STI +#if 0 + call _splx +#endif + addl $4,%esp +/* + * XXX - 0.0 gets here via swtch_to_inactive(). I think 0.1 gets here in the + * same way. Better return a value. + */ + popl %eax # return (p); + ret + +ENTRY(mvesp) + movl %esp,%eax + ret +/* + * struct proc *swtch_to_inactive(p) ; struct proc *p; + * + * At exit of a process, move off the address space of the + * process and onto a "safe" one. Then, on a temporary stack + * return and run code that disposes of the old state. + * Since this code requires a parameter from the "old" stack, + * pass it back as a return value. + */ +ENTRY(swtch_to_inactive) + popl %edx # old pc + popl %eax # arg, our return value + movl _IdlePTD,%ecx + movl %ecx,%cr3 # good bye address space + #write buffer? + movl $tmpstk-4,%esp # temporary stack, compensated for call + jmp %edx # return, execute remainder of cleanup + +/* + * savectx(pcb, altreturn) + * Update pcb, saving current processor state and arranging + * for alternate return ala longjmp in swtch if altreturn is true. + */ +ENTRY(savectx) + movl 4(%esp), %ecx + movw _cpl, %ax + movw %ax, PCB_IML(%ecx) + movl (%esp), %eax + movl %eax, PCB_EIP(%ecx) + movl %ebx, PCB_EBX(%ecx) + movl %esp, PCB_ESP(%ecx) + movl %ebp, PCB_EBP(%ecx) + movl %esi, PCB_ESI(%ecx) + movl %edi, PCB_EDI(%ecx) + +#ifdef NPX + /* + * If npxproc == NULL, then the npx h/w state is irrelevant and the + * state had better already be in the pcb. This is true for forks + * but not for dumps (the old book-keeping with FP flags in the pcb + * always lost for dumps because the dump pcb has 0 flags). + * + * If npxproc != NULL, then we have to save the npx h/w state to + * npxproc's pcb and copy it to the requested pcb, or save to the + * requested pcb and reload. Copying is easier because we would + * have to handle h/w bugs for reloading. We used to lose the + * parent's npx state for forks by forgetting to reload. + */ + mov _npxproc,%eax + testl %eax,%eax + je 1f + + pushl %ecx + movl P_ADDR(%eax),%eax + leal PCB_SAVEFPU(%eax),%eax + pushl %eax + pushl %eax + call _npxsave + popl %eax + popl %eax + popl %ecx + + pushl %ecx + pushl $108+8*2 /* XXX h/w state size + padding */ + leal PCB_SAVEFPU(%ecx),%ecx + pushl %ecx + pushl %eax + call _bcopy + addl $12,%esp + popl %ecx +1: +#endif + + movl _CMAP2, %edx # save temporary map PTE + movl %edx, PCB_CMAP2(%ecx) # in our context + + cmpl $0, 8(%esp) + je 1f + movl %esp, %edx # relocate current sp relative to pcb + subl $_kstack, %edx # (sp is relative to kstack): + addl %edx, %ecx # pcb += sp - kstack; + movl %eax, (%ecx) # write return pc at (relocated) sp@ + # this mess deals with replicating register state gcc hides + movl 12(%esp),%eax + movl %eax,12(%ecx) + movl 16(%esp),%eax + movl %eax,16(%ecx) + movl 20(%esp),%eax + movl %eax,20(%ecx) + movl 24(%esp),%eax + movl %eax,24(%ecx) +1: + xorl %eax, %eax # return 0 + ret + +/* + * addupc(int pc, struct uprof *up, int ticks): + * update profiling information for the user process. + */ + +ENTRY(addupc) + pushl %ebp + movl %esp,%ebp + movl 12(%ebp),%edx /* up */ + movl 8(%ebp),%eax /* pc */ + + subl PR_OFF(%edx),%eax /* pc -= up->pr_off */ + jl L1 /* if (pc < 0) return */ + + shrl $1,%eax /* praddr = pc >> 1 */ + imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */ + shrl $15,%eax /* praddr = praddr << 15 */ + andl $-2,%eax /* praddr &= ~1 */ + + cmpl PR_SIZE(%edx),%eax /* if (praddr > up->pr_size) return */ + ja L1 + +/* addl %eax,%eax /* praddr -> word offset */ + addl PR_BASE(%edx),%eax /* praddr += up-> pr_base */ + movl 16(%ebp),%ecx /* ticks */ + + movl _curpcb,%edx + movl $proffault,PCB_ONFAULT(%edx) + addl %ecx,(%eax) /* storage location += ticks */ + movl $0,PCB_ONFAULT(%edx) +L1: + leave + ret + + ALIGN_TEXT +proffault: + /* if we get a fault, then kill profiling all together */ + movl $0,PCB_ONFAULT(%edx) /* squish the fault handler */ + movl 12(%ebp),%ecx + movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */ + leave + ret + + # To be done: + ENTRY(astoff) + ret + + .data + ALIGN_DATA + .globl _cyloffset, _curpcb +_cyloffset: .long 0 + .globl _proc0paddr +_proc0paddr: .long 0 +LF: .asciz "swtch %x" + ALIGN_DATA + +#if 0 +#define PANIC(msg) xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \ + call _panic; MSG(msg) +#define PRINTF(n,msg) pushal ; nop ; pushl 1f; call _printf; MSG(msg) ; \ + popl %eax ; popal +#define MSG(msg) .data; 1: .asciz msg; ALIGN_DATA; .text +#endif /* 0 */ + +/* + * Trap and fault vector routines + * + * XXX - debugger traps are now interrupt gates so at least bdb doesn't lose + * control. The sti's give the standard losing behaviour for ddb and kgdb. + */ +#define IDTVEC(name) ALIGN_TEXT; .globl _X/**/name; _X/**/name: +#define TRAP(a) pushl $(a) ; jmp alltraps +#ifdef KGDB +#define BPTTRAP(a) sti; pushl $(a) ; jmp bpttraps +#else +#define BPTTRAP(a) sti; TRAP(a) +#endif + + .text +IDTVEC(div) + pushl $0; TRAP(T_DIVIDE) +IDTVEC(dbg) +#ifdef BDBTRAP + BDBTRAP(dbg) +#endif + pushl $0; BPTTRAP(T_TRCTRAP) +IDTVEC(nmi) + pushl $0; TRAP(T_NMI) +IDTVEC(bpt) +#ifdef BDBTRAP + BDBTRAP(bpt) +#endif + pushl $0; BPTTRAP(T_BPTFLT) +IDTVEC(ofl) + pushl $0; TRAP(T_OFLOW) +IDTVEC(bnd) + pushl $0; TRAP(T_BOUND) +IDTVEC(ill) + pushl $0; TRAP(T_PRIVINFLT) +IDTVEC(dna) + pushl $0; TRAP(T_DNA) +IDTVEC(dble) + TRAP(T_DOUBLEFLT) + /*PANIC("Double Fault");*/ +IDTVEC(fpusegm) + pushl $0; TRAP(T_FPOPFLT) +IDTVEC(tss) + TRAP(T_TSSFLT) + /*PANIC("TSS not valid");*/ +IDTVEC(missing) + TRAP(T_SEGNPFLT) +IDTVEC(stk) + TRAP(T_STKFLT) +IDTVEC(prot) + TRAP(T_PROTFLT) +IDTVEC(page) + TRAP(T_PAGEFLT) +IDTVEC(rsvd) + pushl $0; TRAP(T_RESERVED) +IDTVEC(fpu) +#ifdef NPX + /* + * Handle like an interrupt so that we can call npxintr to clear the + * error. It would be better to handle npx interrupts as traps but + * this is difficult for nested interrupts. + */ + pushl $0 /* dummy error code */ + pushl $T_ASTFLT + pushal + nop /* silly, the bug is for popal and it only + * bites when the next instruction has a + * complicated address mode */ + pushl %ds + pushl %es /* now the stack frame is a trap frame */ + movl $KDSEL,%eax + movl %ax,%ds + movl %ax,%es + pushl _cpl + pushl $0 /* dummy unit to finish building intr frame */ + incl _cnt+V_TRAP + call _npxintr + jmp doreti +#else + pushl $0; TRAP(T_ARITHTRAP) +#endif + /* 17 - 31 reserved for future exp */ +IDTVEC(rsvd0) + pushl $0; TRAP(17) +IDTVEC(rsvd1) + pushl $0; TRAP(18) +IDTVEC(rsvd2) + pushl $0; TRAP(19) +IDTVEC(rsvd3) + pushl $0; TRAP(20) +IDTVEC(rsvd4) + pushl $0; TRAP(21) +IDTVEC(rsvd5) + pushl $0; TRAP(22) +IDTVEC(rsvd6) + pushl $0; TRAP(23) +IDTVEC(rsvd7) + pushl $0; TRAP(24) +IDTVEC(rsvd8) + pushl $0; TRAP(25) +IDTVEC(rsvd9) + pushl $0; TRAP(26) +IDTVEC(rsvd10) + pushl $0; TRAP(27) +IDTVEC(rsvd11) + pushl $0; TRAP(28) +IDTVEC(rsvd12) + pushl $0; TRAP(29) +IDTVEC(rsvd13) + pushl $0; TRAP(30) +IDTVEC(rsvd14) + pushl $0; TRAP(31) + + SUPERALIGN_TEXT +alltraps: + pushal + nop + pushl %ds + pushl %es + movl $KDSEL,%eax + movl %ax,%ds + movl %ax,%es +calltrap: + incl _cnt+V_TRAP + call _trap + /* + * Return through doreti to handle ASTs. Have to change trap frame + * to interrupt frame. + */ + movl $T_ASTFLT,4+4+32(%esp) /* new trap type (err code not used) */ + pushl _cpl + pushl $0 /* dummy unit */ + jmp doreti + +#ifdef KGDB +/* + * This code checks for a kgdb trap, then falls through + * to the regular trap code. + */ + ALIGN_TEXT +bpttraps: + pushal + nop + pushl %es + pushl %ds + movl $KDSEL,%eax + movl %ax,%ds + movl %ax,%es + testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp) + # non-kernel mode? + jne calltrap # yes + call _kgdb_trap_glue + jmp calltrap +#endif + +/* + * Call gate entry for syscall + */ + + SUPERALIGN_TEXT +IDTVEC(syscall) + pushfl # only for stupid carry bit and more stupid wait3 cc kludge + # XXX - also for direction flag (bzero, etc. clear it) + pushal # only need eax,ecx,edx - trap resaves others + nop + movl $KDSEL,%eax # switch to kernel segments + movl %ax,%ds + movl %ax,%es + incl _cnt+V_SYSCALL # kml 3/25/93 + call _syscall + /* + * Return through doreti to handle ASTs. Have to change syscall frame + * to interrupt frame. + * + * XXX - we should have set up the frame earlier to avoid the + * following popal/pushal (not much can be done to avoid shuffling + * the flags). Consistent frames would simplify things all over. + */ + movl 32+0(%esp),%eax /* old flags, shuffle to above cs:eip */ + movl 32+4(%esp),%ebx /* `int' frame should have been ef, eip, cs */ + movl 32+8(%esp),%ecx + movl %ebx,32+0(%esp) + movl %ecx,32+4(%esp) + movl %eax,32+8(%esp) + popal + nop + pushl $0 /* dummy error code */ + pushl $T_ASTFLT + pushal + nop + movl __udatasel,%eax /* switch back to user segments */ + push %eax /* XXX - better to preserve originals? */ + push %eax + pushl _cpl + pushl $0 + jmp doreti + +ENTRY(htonl) +ENTRY(ntohl) + movl 4(%esp),%eax +#ifdef i486 + /* XXX */ + /* Since Gas 1.38 does not grok bswap this has been coded as the + * equivalent bytes. This can be changed back to bswap when we + * upgrade to a newer version of Gas */ + /* bswap %eax */ + .byte 0x0f + .byte 0xc8 +#else + xchgb %al,%ah + roll $16,%eax + xchgb %al,%ah +#endif + ret + +ENTRY(htons) +ENTRY(ntohs) + movzwl 4(%esp),%eax + xchgb %al,%ah + ret + +#ifdef SHOW_A_LOT + +/* + * 'show_bits' was too big when defined as a macro. The line length for some + * enclosing macro was too big for gas. Perhaps the code would have blown + * the cache anyway. + */ + + ALIGN_TEXT +show_bits: + pushl %eax + SHOW_BIT(0) + SHOW_BIT(1) + SHOW_BIT(2) + SHOW_BIT(3) + SHOW_BIT(4) + SHOW_BIT(5) + SHOW_BIT(6) + SHOW_BIT(7) + SHOW_BIT(8) + SHOW_BIT(9) + SHOW_BIT(10) + SHOW_BIT(11) + SHOW_BIT(12) + SHOW_BIT(13) + SHOW_BIT(14) + SHOW_BIT(15) + popl %eax + ret + + .data +bit_colors: + .byte GREEN,RED,0,0 + .text + +#endif /* SHOW_A_LOT */ + +#include "i386/isa/vector.s" +#include "i386/isa/icu.s" diff --git a/sys/amd64/amd64/locore.s b/sys/amd64/amd64/locore.s new file mode 100644 index 000000000000..d558dba24a58 --- /dev/null +++ b/sys/amd64/amd64/locore.s @@ -0,0 +1,1830 @@ +/*- + * 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. + * + * @(#)locore.s 7.3 (Berkeley) 5/13/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 5 00158 + * -------------------- ----- ---------------------- + * + * 06 Aug 92 Pace Willisson Allow VGA memory to be mapped + * 28 Nov 92 Frank MacLachlan Aligned addresses and data + * on 32bit boundaries. + * 25 Mar 93 Kevin Lahey Add syscall counter for vmstat + * 20 Apr 93 Bruce Evans New npx-0.5 code + * 25 Apr 93 Bruce Evans Support new interrupt code (intr-0.1) + */ + + +/* + * locore.s: 4BSD machine support for the Intel 386 + * Preliminary version + * Written by William F. Jolitz, 386BSD Project + */ + +#include "assym.s" +#include "machine/psl.h" +#include "machine/pte.h" + +#include "errno.h" + +#include "machine/trap.h" + +#include "machine/specialreg.h" +#include "i386/isa/debug.h" + +#define KDSEL 0x10 +#define SEL_RPL_MASK 0x0003 +#define TRAPF_CS_OFF (13 * 4) + +/* + * Note: This version greatly munged to avoid various assembler errors + * that may be fixed in newer versions of gas. Perhaps newer versions + * will have more pleasant appearance. + */ + + .set IDXSHIFT,10 + .set SYSTEM,0xFE000000 # virtual address of system start + /*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */ + .set SYSPDROFF,0x3F8 # Page dir index of System Base + +#define ALIGN_DATA .align 2 +#define ALIGN_TEXT .align 2,0x90 /* 4-byte boundaries, NOP-filled */ +#define SUPERALIGN_TEXT .align 4,0x90 /* 16-byte boundaries better for 486 */ + +/* NB: NOP now preserves registers so NOPs can be inserted anywhere */ +/* XXX: NOP and FASTER_NOP are misleadingly named */ +#ifdef BROKEN_HARDWARE_AND_OR_SOFTWARE /* XXX - rarely necessary */ +#define FASTER_NOP pushl %eax ; inb $0x84,%al ; popl %eax +#define NOP pushl %eax ; inb $0x84,%al ; inb $0x84,%al ; popl %eax +#else +#define FASTER_NOP +#define NOP +#endif + +/* + * PTmap is recursive pagemap at top of virtual address space. + * Within PTmap, the page directory can be found (third indirection). + */ + .set PDRPDROFF,0x3F7 # Page dir index of Page dir + .globl _PTmap, _PTD, _PTDpde, _Sysmap + .set _PTmap,0xFDC00000 + .set _PTD,0xFDFF7000 + .set _Sysmap,0xFDFF8000 + .set _PTDpde,0xFDFF7000+4*PDRPDROFF + +/* + * APTmap, APTD is the alternate recursive pagemap. + * It's used when modifying another process's page tables. + */ + .set APDRPDROFF,0x3FE # Page dir index of Page dir + .globl _APTmap, _APTD, _APTDpde + .set _APTmap,0xFF800000 + .set _APTD,0xFFBFE000 + .set _APTDpde,0xFDFF7000+4*APDRPDROFF + +/* + * Access to each processes kernel stack is via a region of + * per-process address space (at the beginning), immediatly above + * the user process stack. + */ + .set _kstack, USRSTACK + .globl _kstack + .set PPDROFF,0x3F6 + .set PPTEOFF,0x400-UPAGES # 0x3FE + +#define ENTRY(name) \ + .globl _/**/name; ALIGN_TEXT; _/**/name: +#define ALTENTRY(name) ENTRY(name) + +/* + * Initialization + */ + .data + .globl _cpu,_cold,_boothowto,_bootdev,_cyloffset,_atdevbase,_atdevphys +_cpu: .long 0 # are we 386, 386sx, or 486 +_cold: .long 1 # cold till we are not +_atdevbase: .long 0 # location of start of iomem in virtual +_atdevphys: .long 0 # location of device mapping ptes (phys) + + .globl _IdlePTD, _KPTphys +_IdlePTD: .long 0 +_KPTphys: .long 0 + + .space 512 +tmpstk: + .text + .globl start +start: movw $0x1234,%ax + movw %ax,0x472 # warm boot + jmp 1f + .space 0x500 # skip over warm boot shit + + /* + * pass parameters on stack (howto, bootdev, unit, cyloffset) + * note: (%esp) is return address of boot + * ( if we want to hold onto /boot, it's physical %esp up to _end) + */ + + 1: movl 4(%esp),%eax + movl %eax,_boothowto-SYSTEM + movl 8(%esp),%eax + movl %eax,_bootdev-SYSTEM + movl 12(%esp),%eax + movl %eax, _cyloffset-SYSTEM + + /* + * Finished with old stack; load new %esp now instead of later so + * we can trace this code without having to worry about the trace + * trap clobbering the memory test or the zeroing of the bss+bootstrap + * page tables. + * + * XXX - wdboot clears the bss after testing that this is safe. + * This is too wasteful - memory below 640K is scarce. The boot + * program should check: + * text+data <= &stack_variable - more_space_for_stack + * text+data+bss+pad+space_for_page_tables <= end_of_memory + * Oops, the gdt is in the carcass of the boot program so clearing + * the rest of memory is still not possible. + */ + movl $ tmpstk-SYSTEM,%esp # bootstrap stack end location + +#ifdef garbage + /* count up memory */ + + xorl %eax,%eax # start with base memory at 0x0 + #movl $ 0xA0000/NBPG,%ecx # look every 4K up to 640K + movl $ 0xA0,%ecx # look every 4K up to 640K +1: movl (%eax),%ebx # save location to check + movl $0xa55a5aa5,(%eax) # write test pattern + /* flush stupid cache here! (with bcopy (0,0,512*1024) ) */ + cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover + jne 2f + movl %ebx,(%eax) # restore memory + addl $ NBPG,%eax + loop 1b +2: shrl $12,%eax + movl %eax,_Maxmem-SYSTEM + + movl $0x100000,%eax # next, talley remaining memory + #movl $((0xFFF000-0x100000)/NBPG),%ecx + movl $(0xFFF-0x100),%ecx +1: movl (%eax),%ebx # save location to check + movl $0xa55a5aa5,(%eax) # write test pattern + cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover + jne 2f + movl %ebx,(%eax) # restore memory + addl $ NBPG,%eax + loop 1b +2: shrl $12,%eax + movl %eax,_Maxmem-SYSTEM +#endif + +/* find end of kernel image */ + movl $_end-SYSTEM,%ecx + addl $ NBPG-1,%ecx + andl $~(NBPG-1),%ecx + movl %ecx,%esi + +/* clear bss and memory for bootstrap pagetables. */ + movl $_edata-SYSTEM,%edi + subl %edi,%ecx + addl $(UPAGES+5)*NBPG,%ecx +/* + * Virtual address space of kernel: + * + * text | data | bss | page dir | proc0 kernel stack | usr stk map | Sysmap + * 0 1 2 3 4 + */ + xorl %eax,%eax # pattern + cld + rep + stosb + + movl %esi,_IdlePTD-SYSTEM /*physical address of Idle Address space */ + +#define fillkpt \ +1: movl %eax,(%ebx) ; \ + addl $ NBPG,%eax ; /* increment physical address */ \ + addl $4,%ebx ; /* next pte */ \ + loop 1b ; + +/* + * Map Kernel + * N.B. don't bother with making kernel text RO, as 386 + * ignores R/W AND U/S bits on kernel access (only v works) ! + * + * First step - build page tables + */ + movl %esi,%ecx # this much memory, + shrl $ PGSHIFT,%ecx # for this many pte s + addl $ UPAGES+4,%ecx # including our early context + movl $0xa0,%ecx # XXX - cover debugger pages + movl $PG_V|PG_KW,%eax # having these bits set, + lea (4*NBPG)(%esi),%ebx # physical address of KPT in proc 0, + movl %ebx,_KPTphys-SYSTEM # in the kernel page table, + fillkpt + +/* map I/O memory map */ + + movl $0x100-0xa0,%ecx # for this many pte s, + movl $(0xa0000|PG_V|PG_UW),%eax # having these bits set,(perhaps URW?) XXX 06 Aug 92 + movl %ebx,_atdevphys-SYSTEM # remember phys addr of ptes + fillkpt + + /* map proc 0's kernel stack into user page table page */ + + movl $ UPAGES,%ecx # for this many pte s, + lea (1*NBPG)(%esi),%eax # physical address in proc 0 + lea (SYSTEM)(%eax),%edx + movl %edx,_proc0paddr-SYSTEM # remember VA for 0th process init + orl $PG_V|PG_KW,%eax # having these bits set, + lea (3*NBPG)(%esi),%ebx # physical address of stack pt in proc 0 + addl $(PPTEOFF*4),%ebx + fillkpt + +/* + * Construct a page table directory + * (of page directory elements - pde's) + */ + /* install a pde for temporary double map of bottom of VA */ + lea (4*NBPG)(%esi),%eax # physical address of kernel page table + orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92 + movl %eax,(%esi) # which is where temp maps! + + /* kernel pde's */ + movl $ 3,%ecx # for this many pde s, + lea (SYSPDROFF*4)(%esi), %ebx # offset of pde for kernel + fillkpt + + /* install a pde recursively mapping page directory as a page table! */ + movl %esi,%eax # phys address of ptd in proc 0 + orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92 + movl %eax, PDRPDROFF*4(%esi) # which is where PTmap maps! + + /* install a pde to map kernel stack for proc 0 */ + lea (3*NBPG)(%esi),%eax # physical address of pt in proc 0 + orl $PG_V|PG_KW,%eax # pde entry is valid + movl %eax,PPDROFF*4(%esi) # which is where kernel stack maps! + + /* copy and convert stuff from old gdt and idt for debugger */ + + cmpl $0x0375c339,0x96104 # XXX - debugger signature + jne 1f + movb $1,_bdb_exists-SYSTEM +1: + pushal + subl $2*6,%esp + + sgdt (%esp) + movl 2(%esp),%esi # base address of current gdt + movl $_gdt-SYSTEM,%edi + movl %edi,2(%esp) + movl $8*18/4,%ecx + rep # copy gdt + movsl + movl $_gdt-SYSTEM,-8+2(%edi) # adjust gdt self-ptr + movb $0x92,-8+5(%edi) + + sidt 6(%esp) + movl 6+2(%esp),%esi # base address of current idt + movl 8+4(%esi),%eax # convert dbg descriptor to ... + movw 8(%esi),%ax + movl %eax,bdb_dbg_ljmp+1-SYSTEM # ... immediate offset ... + movl 8+2(%esi),%eax + movw %ax,bdb_dbg_ljmp+5-SYSTEM # ... and selector for ljmp + movl 24+4(%esi),%eax # same for bpt descriptor + movw 24(%esi),%ax + movl %eax,bdb_bpt_ljmp+1-SYSTEM + movl 24+2(%esi),%eax + movw %ax,bdb_bpt_ljmp+5-SYSTEM + + movl $_idt-SYSTEM,%edi + movl %edi,6+2(%esp) + movl $8*4/4,%ecx + rep # copy idt + movsl + + lgdt (%esp) + lidt 6(%esp) + + addl $2*6,%esp + popal + + /* load base of page directory, and enable mapping */ + movl %esi,%eax # phys address of ptd in proc 0 + orl $ I386_CR3PAT,%eax + movl %eax,%cr3 # load ptd addr into mmu + movl %cr0,%eax # get control word +#ifdef USE_486_WRITE_PROTECT + orl $CR0_PE|CR0_PG|CR0_WP,%eax # and let s page! +#else + orl $CR0_PE|CR0_PG,%eax # and let s page! +#endif + movl %eax,%cr0 # NOW! + + pushl $begin # jump to high mem! + ret + +begin: /* now running relocated at SYSTEM where the system is linked to run */ + + .globl _Crtat + movl _Crtat,%eax + subl $0xfe0a0000,%eax + movl _atdevphys,%edx # get pte PA + subl _KPTphys,%edx # remove base of ptes, now have phys offset + shll $ PGSHIFT-2,%edx # corresponding to virt offset + addl $ SYSTEM,%edx # add virtual base + movl %edx, _atdevbase + addl %eax,%edx + movl %edx,_Crtat + + /* set up bootstrap stack */ + movl $ _kstack+UPAGES*NBPG-4*12,%esp # bootstrap stack end location + xorl %eax,%eax # mark end of frames + movl %eax,%ebp + movl _proc0paddr, %eax + movl %esi, PCB_CR3(%eax) + + lea 7*NBPG(%esi),%esi # skip past stack. + pushl %esi + + /* relocate debugger gdt entries */ + + movl $_gdt+8*9,%eax # adjust slots 9-17 + movl $9,%ecx +reloc_gdt: + movb $0xfe,7(%eax) # top byte of base addresses, was 0, + addl $8,%eax # now SYSTEM>>24 + loop reloc_gdt + + cmpl $0,_bdb_exists + je 1f + int $3 +1: + + call _init386 # wire 386 chip for unix operation + + movl $0,_PTD + call _main + popl %esi + + .globl __ucodesel,__udatasel + movl __ucodesel,%eax + movl __udatasel,%ecx + # build outer stack frame + pushl %ecx # user ss + pushl $ USRSTACK # user esp + pushl %eax # user cs + pushl $0 # user ip + movl %cx,%ds + movl %cx,%es + movl %ax,%fs # double map cs to fs + movl %cx,%gs # and ds to gs + lret # goto user! + + pushl $lretmsg1 /* "should never get here!" */ + call _panic +lretmsg1: + .asciz "lret: toinit\n" + + + .set exec,59 + .set exit,1 + +#define LCALL(x,y) .byte 0x9a ; .long y; .word x +/* + * Icode is copied out to process 1 to exec /etc/init. + * If the exec fails, process 1 exits. + */ +ENTRY(icode) + # pushl $argv-_icode # gas fucks up again + movl $argv,%eax + subl $_icode,%eax + pushl %eax + + # pushl $init-_icode + movl $init,%eax + subl $_icode,%eax + pushl %eax + pushl %eax # dummy out rta + + movl %esp,%ebp + movl $exec,%eax + LCALL(0x7,0x0) + pushl %eax + movl $exit,%eax + pushl %eax # dummy out rta + LCALL(0x7,0x0) + +init: + .asciz "/sbin/init" + ALIGN_DATA +argv: + .long init+6-_icode # argv[0] = "init" ("/sbin/init" + 6) + .long eicode-_icode # argv[1] follows icode after copyout + .long 0 +eicode: + + .globl _szicode +_szicode: + .long _szicode-_icode + +ENTRY(sigcode) + call 12(%esp) + lea 28(%esp),%eax # scp (the call may have clobbered the + # copy at 8(%esp)) + # XXX - use genassym + pushl %eax + pushl %eax # junk to fake return address + movl $103,%eax # sigreturn() + LCALL(0x7,0) # enter kernel with args on stack + hlt # never gets here + + .globl _szsigcode +_szsigcode: + .long _szsigcode-_sigcode + + /* + * Support routines for GCC + */ +ENTRY(__udivsi3) + movl 4(%esp),%eax + xorl %edx,%edx + divl 8(%esp) + ret + +ENTRY(__divsi3) + movl 4(%esp),%eax + cltd + idivl 8(%esp) + ret + + /* + * I/O bus instructions via C + */ +ENTRY(inb) + movl 4(%esp),%edx + subl %eax,%eax # clr eax + NOP + inb %dx,%al + ret + + +ENTRY(inw) + movl 4(%esp),%edx + subl %eax,%eax # clr eax + NOP + inw %dx,%ax + ret + + +ENTRY(rtcin) + movl 4(%esp),%eax + outb %al,$0x70 + subl %eax,%eax # clr eax + inb $0x71,%al + ret + +ENTRY(outb) + movl 4(%esp),%edx + NOP + movl 8(%esp),%eax + outb %al,%dx + NOP + ret + +ENTRY(outw) + movl 4(%esp),%edx + NOP + movl 8(%esp),%eax + outw %ax,%dx + NOP + ret + + /* + * void bzero(void *base, u_int cnt) + */ + +ENTRY(bzero) + pushl %edi + movl 8(%esp),%edi + movl 12(%esp),%ecx + xorl %eax,%eax + shrl $2,%ecx + cld + rep + stosl + movl 12(%esp),%ecx + andl $3,%ecx + rep + stosb + popl %edi + ret + + /* + * fillw (pat,base,cnt) + */ + +ENTRY(fillw) + pushl %edi + movl 8(%esp),%eax + movl 12(%esp),%edi + movl 16(%esp),%ecx + cld + rep + stosw + popl %edi + ret + +ENTRY(bcopyb) + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + cmpl %esi,%edi /* potentially overlapping? */ + jnb 1f + cld /* nope, copy forwards */ + rep + movsb + popl %edi + popl %esi + ret + + ALIGN_TEXT +1: + addl %ecx,%edi /* copy backwards. */ + addl %ecx,%esi + std + decl %edi + decl %esi + rep + movsb + popl %edi + popl %esi + cld + ret + +ENTRY(bcopyw) + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + cmpl %esi,%edi /* potentially overlapping? */ + jnb 1f + cld /* nope, copy forwards */ + shrl $1,%ecx /* copy by 16-bit words */ + rep + movsw + adc %ecx,%ecx /* any bytes left? */ + rep + movsb + popl %edi + popl %esi + ret + + ALIGN_TEXT +1: + addl %ecx,%edi /* copy backwards */ + addl %ecx,%esi + std + andl $1,%ecx /* any fractional bytes? */ + decl %edi + decl %esi + rep + movsb + movl 20(%esp),%ecx /* copy remainder by 16-bit words */ + shrl $1,%ecx + decl %esi + decl %edi + rep + movsw + popl %edi + popl %esi + cld + ret + +ENTRY(bcopyx) + movl 16(%esp),%eax + cmpl $2,%eax + je _bcopyw + cmpl $4,%eax + jne _bcopyb + /* + * Fall through to bcopy. ENTRY() provides harmless fill bytes. + */ + + /* + * (ov)bcopy (src,dst,cnt) + * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800 + * Changed by bde to not bother returning %eax = 0. + */ + +ENTRY(ovbcopy) +ENTRY(bcopy) + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + cmpl %esi,%edi /* potentially overlapping? */ + jnb 1f + cld /* nope, copy forwards */ + shrl $2,%ecx /* copy by 32-bit words */ + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx /* any bytes left? */ + rep + movsb + popl %edi + popl %esi + ret + + ALIGN_TEXT +1: + addl %ecx,%edi /* copy backwards */ + addl %ecx,%esi + std + andl $3,%ecx /* any fractional bytes? */ + decl %edi + decl %esi + rep + movsb + movl 20(%esp),%ecx /* copy remainder by 32-bit words */ + shrl $2,%ecx + subl $3,%esi + subl $3,%edi + rep + movsl + popl %edi + popl %esi + cld + ret + +#ifdef notdef +ENTRY(copyout) + movl _curpcb, %eax + movl $cpyflt, PCB_ONFAULT(%eax) # in case we page/protection violate + pushl %esi + pushl %edi + pushl %ebx + movl 16(%esp), %esi + movl 20(%esp), %edi + movl 24(%esp), %ebx + + /* first, check to see if "write fault" */ +1: movl %edi, %eax +#ifdef notyet + shrl $IDXSHIFT, %eax /* fetch pte associated with address */ + andb $0xfc, %al + movl _PTmap(%eax), %eax + + andb $7, %al /* if we are the one case that won't trap... */ + cmpb $5, %al + jne 2f + /* ... then simulate the trap! */ + pushl %edi + call _trapwrite /* trapwrite(addr) */ + popl %edx + + cmpl $0, %eax /* if not ok, return */ + jne cpyflt + /* otherwise, continue with reference */ +2: + movl %edi, %eax /* calculate remainder this pass */ + andl $0xfffff000, %eax + movl $NBPG, %ecx + subl %eax, %ecx + cmpl %ecx, %ebx + jle 3f + movl %ebx, %ecx +3: subl %ecx, %ebx + movl %ecx, %edx +#else + movl %ebx, %ecx + movl %ebx, %edx +#endif + + shrl $2,%ecx /* movem */ + cld + rep + movsl + movl %edx, %ecx /* don't depend on ecx here! */ + andl $3, %ecx + rep + movsb + +#ifdef notyet + cmpl $0, %ebx + jl 1b +#endif + + popl %ebx + popl %edi + popl %esi + xorl %eax,%eax + movl _curpcb,%edx + movl %eax,PCB_ONFAULT(%edx) + ret + +ENTRY(copyin) + movl _curpcb,%eax + movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate + pushl %esi + pushl %edi + pushl %ebx # XXX - not used, but affects stack offsets + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + shrl $2,%ecx + cld + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx + rep + movsb + popl %ebx + popl %edi + popl %esi + xorl %eax,%eax + movl _curpcb,%edx + movl %eax,PCB_ONFAULT(%edx) + ret + + ALIGN_TEXT +cpyflt: + popl %ebx + popl %edi + popl %esi + movl _curpcb,%edx + movl $0,PCB_ONFAULT(%edx) + movl $ EFAULT,%eax + ret +#else +ENTRY(copyout) + movl _curpcb,%eax + movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + shrl $2,%ecx + cld + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx + rep + movsb + popl %edi + popl %esi + xorl %eax,%eax + movl _curpcb,%edx + movl %eax,PCB_ONFAULT(%edx) + ret + +ENTRY(copyin) + movl _curpcb,%eax + movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + shrl $2,%ecx + cld + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx + rep + movsb + popl %edi + popl %esi + xorl %eax,%eax + movl _curpcb,%edx + movl %eax,PCB_ONFAULT(%edx) + ret + + ALIGN_TEXT +cpyflt: popl %edi + popl %esi + movl _curpcb,%edx + movl $0,PCB_ONFAULT(%edx) + movl $ EFAULT,%eax + ret + +#endif + + # insb(port,addr,cnt) +ENTRY(insb) + pushl %edi + movw 8(%esp),%dx + movl 12(%esp),%edi + movl 16(%esp),%ecx + cld + NOP + rep + insb + NOP + movl %edi,%eax + popl %edi + ret + + # insw(port,addr,cnt) +ENTRY(insw) + pushl %edi + movw 8(%esp),%dx + movl 12(%esp),%edi + movl 16(%esp),%ecx + cld + NOP + .byte 0x66,0xf2,0x6d # rep insw + NOP + movl %edi,%eax + popl %edi + ret + + # outsw(port,addr,cnt) +ENTRY(outsw) + pushl %esi + movw 8(%esp),%dx + movl 12(%esp),%esi + movl 16(%esp),%ecx + cld + NOP + .byte 0x66,0xf2,0x6f # rep outsw + NOP + movl %esi,%eax + popl %esi + ret + + # outsb(port,addr,cnt) +ENTRY(outsb) + pushl %esi + movw 8(%esp),%dx + movl 12(%esp),%esi + movl 16(%esp),%ecx + cld + NOP + rep + outsb + NOP + movl %esi,%eax + popl %esi + ret + + /* + * void lgdt(struct region_descriptor *rdp); + */ +ENTRY(lgdt) + /* reload the descriptor table */ + movl 4(%esp),%eax + lgdt (%eax) + /* flush the prefetch q */ + jmp 1f + nop +1: + /* reload "stale" selectors */ + movl $KDSEL,%eax + movl %ax,%ds + movl %ax,%es + movl %ax,%ss + + /* reload code selector by turning return into intersegmental return */ + movl (%esp),%eax + pushl %eax + # movl $KCSEL,4(%esp) + movl $8,4(%esp) + lret + + /* + * void lidt(struct region_descriptor *rdp); + */ +ENTRY(lidt) + movl 4(%esp),%eax + lidt (%eax) + ret + + /* + * void lldt(u_short sel) + */ +ENTRY(lldt) + lldt 4(%esp) + ret + + /* + * void ltr(u_short sel) + */ +ENTRY(ltr) + ltr 4(%esp) + ret + + /* + * void lcr3(caddr_t cr3) + */ + ALIGN_TEXT +ENTRY(load_cr3) +ALTENTRY(lcr3) + movl 4(%esp),%eax + orl $ I386_CR3PAT,%eax + movl %eax,%cr3 + ret + + # tlbflush() +ENTRY(tlbflush) + movl %cr3,%eax + orl $ I386_CR3PAT,%eax + movl %eax,%cr3 + ret + + # lcr0(cr0) +ENTRY(lcr0) +ALTENTRY(load_cr0) + movl 4(%esp),%eax + movl %eax,%cr0 + ret + + # rcr0() +ENTRY(rcr0) + movl %cr0,%eax + ret + + # rcr2() +ENTRY(rcr2) + movl %cr2,%eax + ret + + # rcr3() +ENTRY(_cr3) +ALTENTRY(rcr3) + movl %cr3,%eax + ret + + # ssdtosd(*ssdp,*sdp) +ENTRY(ssdtosd) + pushl %ebx + movl 8(%esp),%ecx + movl 8(%ecx),%ebx + shll $16,%ebx + movl (%ecx),%edx + roll $16,%edx + movb %dh,%bl + movb %dl,%bh + rorl $8,%ebx + movl 4(%ecx),%eax + movw %ax,%dx + andl $0xf0000,%eax + orl %eax,%ebx + movl 12(%esp),%ecx + movl %edx,(%ecx) + movl %ebx,4(%ecx) + popl %ebx + ret + +/* + * {fu,su},{byte,word} + */ +ALTENTRY(fuiword) +ENTRY(fuword) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) + movl 4(%esp),%edx + .byte 0x65 # use gs + movl (%edx),%eax + movl $0,PCB_ONFAULT(%ecx) + ret + +ENTRY(fusword) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + .byte 0x65 # use gs + movzwl (%edx),%eax + movl $0,PCB_ONFAULT(%ecx) + ret + +ALTENTRY(fuibyte) +ENTRY(fubyte) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + .byte 0x65 # use gs + movzbl (%edx),%eax + movl $0,PCB_ONFAULT(%ecx) + ret + + ALIGN_TEXT +fusufault: + movl _curpcb,%ecx + xorl %eax,%eax + movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate + decl %eax + ret + +ALTENTRY(suiword) +ENTRY(suword) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + movl 8(%esp),%eax + +#ifdef notdef + shrl $IDXSHIFT, %edx /* fetch pte associated with address */ + andb $0xfc, %dl + movl _PTmap(%edx), %edx + + andb $7, %dl /* if we are the one case that won't trap... */ + cmpb $5 , %edx + jne 1f + /* ... then simulate the trap! */ + pushl %edi + call _trapwrite /* trapwrite(addr) */ + popl %edx + cmpl $0, %eax /* if not ok, return */ + jne fusufault + movl 8(%esp),%eax /* otherwise, continue with reference */ +1: + movl 4(%esp),%edx +#endif + .byte 0x65 # use gs + movl %eax,(%edx) + xorl %eax,%eax + movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate + ret + +ENTRY(susword) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + movl 8(%esp),%eax +#ifdef notdef +shrl $IDXSHIFT, %edx /* calculate pte address */ +andb $0xfc, %dl +movl _PTmap(%edx), %edx +andb $7, %edx /* if we are the one case that won't trap... */ +cmpb $5 , %edx +jne 1f +/* ..., then simulate the trap! */ + pushl %edi + call _trapwrite /* trapwrite(addr) */ + popl %edx +movl _curpcb, %ecx # restore trashed registers +cmpl $0, %eax /* if not ok, return */ +jne fusufault +movl 8(%esp),%eax +1: movl 4(%esp),%edx +#endif + .byte 0x65 # use gs + movw %ax,(%edx) + xorl %eax,%eax + movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate + ret + +ALTENTRY(suibyte) +ENTRY(subyte) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + movl 8(%esp),%eax +#ifdef notdef +shrl $IDXSHIFT, %edx /* calculate pte address */ +andb $0xfc, %dl +movl _PTmap(%edx), %edx +andb $7, %edx /* if we are the one case that won't trap... */ +cmpb $5 , %edx +jne 1f +/* ..., then simulate the trap! */ + pushl %edi + call _trapwrite /* trapwrite(addr) */ + popl %edx +movl _curpcb, %ecx # restore trashed registers +cmpl $0, %eax /* if not ok, return */ +jne fusufault +movl 8(%esp),%eax +1: movl 4(%esp),%edx +#endif + .byte 0x65 # use gs + movb %eax,(%edx) + xorl %eax,%eax + movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate + ret + +ENTRY(setjmp) + movl 4(%esp),%eax + movl %ebx, (%eax) # save ebx + movl %esp, 4(%eax) # save esp + movl %ebp, 8(%eax) # save ebp + movl %esi,12(%eax) # save esi + movl %edi,16(%eax) # save edi + movl (%esp),%edx # get rta + movl %edx,20(%eax) # save eip + xorl %eax,%eax # return (0); + ret + +ENTRY(longjmp) + movl 4(%esp),%eax + movl (%eax),%ebx # restore ebx + movl 4(%eax),%esp # restore esp + movl 8(%eax),%ebp # restore ebp + movl 12(%eax),%esi # restore esi + movl 16(%eax),%edi # restore edi + movl 20(%eax),%edx # get rta + movl %edx,(%esp) # put in return frame + xorl %eax,%eax # return (1); + incl %eax + ret +/* + * The following primitives manipulate the run queues. + * _whichqs tells which of the 32 queues _qs + * have processes in them. Setrq 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_pri, divided by 4 + * actually to shrink the 0-127 range of priorities into the 32 available + * queues. + */ + + .globl _whichqs,_qs,_cnt,_panic + .comm _noproc,4 + .comm _runrun,4 + +/* + * Setrq(p) + * + * Call should be made at spl6(), and p->p_stat should be SRUN + */ +ENTRY(setrq) + movl 4(%esp),%eax + cmpl $0,P_RLINK(%eax) # should not be on q already + je set1 + pushl $set2 + call _panic +set1: + movzbl P_PRI(%eax),%edx + shrl $2,%edx + btsl %edx,_whichqs # set q full bit + shll $3,%edx + addl $_qs,%edx # locate q hdr + movl %edx,P_LINK(%eax) # link process on tail of q + movl P_RLINK(%edx),%ecx + movl %ecx,P_RLINK(%eax) + movl %eax,P_RLINK(%edx) + movl %eax,P_LINK(%ecx) + ret + +set2: .asciz "setrq" + +/* + * Remrq(p) + * + * Call should be made at spl6(). + */ +ENTRY(remrq) + movl 4(%esp),%eax + movzbl P_PRI(%eax),%edx + shrl $2,%edx + btrl %edx,_whichqs # clear full bit, panic if clear already + jb rem1 + pushl $rem3 + call _panic +rem1: + pushl %edx + movl P_LINK(%eax),%ecx # unlink process + movl P_RLINK(%eax),%edx + movl %edx,P_RLINK(%ecx) + movl P_RLINK(%eax),%ecx + movl P_LINK(%eax),%edx + movl %edx,P_LINK(%ecx) + popl %edx + movl $_qs,%ecx + shll $3,%edx + addl %edx,%ecx + cmpl P_LINK(%ecx),%ecx # q still has something? + je rem2 + shrl $3,%edx # yes, set bit as still full + btsl %edx,_whichqs +rem2: + movl $0,P_RLINK(%eax) # zap reverse link to indicate off list + ret + +rem3: .asciz "remrq" +sw0: .asciz "swtch" + +/* + * When no processes are on the runq, Swtch branches to idle + * to wait for something to come ready. + */ + .globl Idle + ALIGN_TEXT +Idle: +sti_for_idle: + sti + SHOW_STI + ALIGN_TEXT +idle: + call _spl0 + cmpl $0,_whichqs + jne sw1 + hlt # wait for interrupt + jmp idle + + SUPERALIGN_TEXT /* so profiling doesn't lump Idle with swtch().. */ +badsw: + pushl $sw0 + call _panic + /*NOTREACHED*/ + +/* + * Swtch() + */ +ENTRY(swtch) + + incl _cnt+V_SWTCH + + /* switch to new process. first, save context as needed */ + + movl _curproc,%ecx + + /* if no process to save, don't bother */ + testl %ecx,%ecx + je sw1 + + movl P_ADDR(%ecx),%ecx + + movl (%esp),%eax # Hardware registers + movl %eax, PCB_EIP(%ecx) + movl %ebx, PCB_EBX(%ecx) + movl %esp, PCB_ESP(%ecx) + movl %ebp, PCB_EBP(%ecx) + movl %esi, PCB_ESI(%ecx) + movl %edi, PCB_EDI(%ecx) + +#ifdef NPX + /* have we used fp, and need a save? */ + mov _curproc,%eax + cmp %eax,_npxproc + jne 1f + pushl %ecx /* h/w bugs make saving complicated */ + leal PCB_SAVEFPU(%ecx),%eax + pushl %eax + call _npxsave /* do it in a big C function */ + popl %eax + popl %ecx +1: +#endif + + movl _CMAP2,%eax # save temporary map PTE + movl %eax,PCB_CMAP2(%ecx) # in our context + movl $0,_curproc # out of process + + # movw _cpl, %ax + # movw %ax, PCB_IML(%ecx) # save ipl + + /* save is done, now choose a new process or idle */ +sw1: + cli + SHOW_CLI + movl _whichqs,%edi +2: + # XXX - bsf is sloow + bsfl %edi,%eax # find a full q + je sti_for_idle # if none, idle + # XX update whichqs? +swfnd: + btrl %eax,%edi # clear q full status + jnb 2b # if it was clear, look for another + movl %eax,%ebx # save which one we are using + + shll $3,%eax + addl $_qs,%eax # select q + movl %eax,%esi + +#ifdef DIAGNOSTIC + cmpl P_LINK(%eax),%eax # linked to self? (e.g. not on list) + je badsw # not possible +#endif + + movl P_LINK(%eax),%ecx # unlink from front of process q + movl P_LINK(%ecx),%edx + movl %edx,P_LINK(%eax) + movl P_RLINK(%ecx),%eax + movl %eax,P_RLINK(%edx) + + cmpl P_LINK(%ecx),%esi # q empty + je 3f + btsl %ebx,%edi # nope, set to indicate full +3: + movl %edi,_whichqs # update q status + + movl $0,%eax + movl %eax,_want_resched + +#ifdef DIAGNOSTIC + cmpl %eax,P_WCHAN(%ecx) + jne badsw + cmpb $ SRUN,P_STAT(%ecx) + jne badsw +#endif + + movl %eax,P_RLINK(%ecx) /* isolate process to run */ + movl P_ADDR(%ecx),%edx + movl PCB_CR3(%edx),%ebx + + /* switch address space */ + movl %ebx,%cr3 + + /* restore context */ + movl PCB_EBX(%edx), %ebx + movl PCB_ESP(%edx), %esp + movl PCB_EBP(%edx), %ebp + movl PCB_ESI(%edx), %esi + movl PCB_EDI(%edx), %edi + movl PCB_EIP(%edx), %eax + movl %eax, (%esp) + + movl PCB_CMAP2(%edx),%eax # get temporary map + movl %eax,_CMAP2 # reload temporary map PTE + + movl %ecx,_curproc # into next process + movl %edx,_curpcb + + pushl %edx # save p to return +/* + * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1? + * I think restoring the cpl is unnecessary, but we must turn off the cli + * now that spl*() don't do it as a side affect. + */ + pushl PCB_IML(%edx) + sti + SHOW_STI +#if 0 + call _splx +#endif + addl $4,%esp +/* + * XXX - 0.0 gets here via swtch_to_inactive(). I think 0.1 gets here in the + * same way. Better return a value. + */ + popl %eax # return (p); + ret + +ENTRY(mvesp) + movl %esp,%eax + ret +/* + * struct proc *swtch_to_inactive(p) ; struct proc *p; + * + * At exit of a process, move off the address space of the + * process and onto a "safe" one. Then, on a temporary stack + * return and run code that disposes of the old state. + * Since this code requires a parameter from the "old" stack, + * pass it back as a return value. + */ +ENTRY(swtch_to_inactive) + popl %edx # old pc + popl %eax # arg, our return value + movl _IdlePTD,%ecx + movl %ecx,%cr3 # good bye address space + #write buffer? + movl $tmpstk-4,%esp # temporary stack, compensated for call + jmp %edx # return, execute remainder of cleanup + +/* + * savectx(pcb, altreturn) + * Update pcb, saving current processor state and arranging + * for alternate return ala longjmp in swtch if altreturn is true. + */ +ENTRY(savectx) + movl 4(%esp), %ecx + movw _cpl, %ax + movw %ax, PCB_IML(%ecx) + movl (%esp), %eax + movl %eax, PCB_EIP(%ecx) + movl %ebx, PCB_EBX(%ecx) + movl %esp, PCB_ESP(%ecx) + movl %ebp, PCB_EBP(%ecx) + movl %esi, PCB_ESI(%ecx) + movl %edi, PCB_EDI(%ecx) + +#ifdef NPX + /* + * If npxproc == NULL, then the npx h/w state is irrelevant and the + * state had better already be in the pcb. This is true for forks + * but not for dumps (the old book-keeping with FP flags in the pcb + * always lost for dumps because the dump pcb has 0 flags). + * + * If npxproc != NULL, then we have to save the npx h/w state to + * npxproc's pcb and copy it to the requested pcb, or save to the + * requested pcb and reload. Copying is easier because we would + * have to handle h/w bugs for reloading. We used to lose the + * parent's npx state for forks by forgetting to reload. + */ + mov _npxproc,%eax + testl %eax,%eax + je 1f + + pushl %ecx + movl P_ADDR(%eax),%eax + leal PCB_SAVEFPU(%eax),%eax + pushl %eax + pushl %eax + call _npxsave + popl %eax + popl %eax + popl %ecx + + pushl %ecx + pushl $108+8*2 /* XXX h/w state size + padding */ + leal PCB_SAVEFPU(%ecx),%ecx + pushl %ecx + pushl %eax + call _bcopy + addl $12,%esp + popl %ecx +1: +#endif + + movl _CMAP2, %edx # save temporary map PTE + movl %edx, PCB_CMAP2(%ecx) # in our context + + cmpl $0, 8(%esp) + je 1f + movl %esp, %edx # relocate current sp relative to pcb + subl $_kstack, %edx # (sp is relative to kstack): + addl %edx, %ecx # pcb += sp - kstack; + movl %eax, (%ecx) # write return pc at (relocated) sp@ + # this mess deals with replicating register state gcc hides + movl 12(%esp),%eax + movl %eax,12(%ecx) + movl 16(%esp),%eax + movl %eax,16(%ecx) + movl 20(%esp),%eax + movl %eax,20(%ecx) + movl 24(%esp),%eax + movl %eax,24(%ecx) +1: + xorl %eax, %eax # return 0 + ret + +/* + * addupc(int pc, struct uprof *up, int ticks): + * update profiling information for the user process. + */ + +ENTRY(addupc) + pushl %ebp + movl %esp,%ebp + movl 12(%ebp),%edx /* up */ + movl 8(%ebp),%eax /* pc */ + + subl PR_OFF(%edx),%eax /* pc -= up->pr_off */ + jl L1 /* if (pc < 0) return */ + + shrl $1,%eax /* praddr = pc >> 1 */ + imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */ + shrl $15,%eax /* praddr = praddr << 15 */ + andl $-2,%eax /* praddr &= ~1 */ + + cmpl PR_SIZE(%edx),%eax /* if (praddr > up->pr_size) return */ + ja L1 + +/* addl %eax,%eax /* praddr -> word offset */ + addl PR_BASE(%edx),%eax /* praddr += up-> pr_base */ + movl 16(%ebp),%ecx /* ticks */ + + movl _curpcb,%edx + movl $proffault,PCB_ONFAULT(%edx) + addl %ecx,(%eax) /* storage location += ticks */ + movl $0,PCB_ONFAULT(%edx) +L1: + leave + ret + + ALIGN_TEXT +proffault: + /* if we get a fault, then kill profiling all together */ + movl $0,PCB_ONFAULT(%edx) /* squish the fault handler */ + movl 12(%ebp),%ecx + movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */ + leave + ret + + # To be done: + ENTRY(astoff) + ret + + .data + ALIGN_DATA + .globl _cyloffset, _curpcb +_cyloffset: .long 0 + .globl _proc0paddr +_proc0paddr: .long 0 +LF: .asciz "swtch %x" + ALIGN_DATA + +#if 0 +#define PANIC(msg) xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \ + call _panic; MSG(msg) +#define PRINTF(n,msg) pushal ; nop ; pushl 1f; call _printf; MSG(msg) ; \ + popl %eax ; popal +#define MSG(msg) .data; 1: .asciz msg; ALIGN_DATA; .text +#endif /* 0 */ + +/* + * Trap and fault vector routines + * + * XXX - debugger traps are now interrupt gates so at least bdb doesn't lose + * control. The sti's give the standard losing behaviour for ddb and kgdb. + */ +#define IDTVEC(name) ALIGN_TEXT; .globl _X/**/name; _X/**/name: +#define TRAP(a) pushl $(a) ; jmp alltraps +#ifdef KGDB +#define BPTTRAP(a) sti; pushl $(a) ; jmp bpttraps +#else +#define BPTTRAP(a) sti; TRAP(a) +#endif + + .text +IDTVEC(div) + pushl $0; TRAP(T_DIVIDE) +IDTVEC(dbg) +#ifdef BDBTRAP + BDBTRAP(dbg) +#endif + pushl $0; BPTTRAP(T_TRCTRAP) +IDTVEC(nmi) + pushl $0; TRAP(T_NMI) +IDTVEC(bpt) +#ifdef BDBTRAP + BDBTRAP(bpt) +#endif + pushl $0; BPTTRAP(T_BPTFLT) +IDTVEC(ofl) + pushl $0; TRAP(T_OFLOW) +IDTVEC(bnd) + pushl $0; TRAP(T_BOUND) +IDTVEC(ill) + pushl $0; TRAP(T_PRIVINFLT) +IDTVEC(dna) + pushl $0; TRAP(T_DNA) +IDTVEC(dble) + TRAP(T_DOUBLEFLT) + /*PANIC("Double Fault");*/ +IDTVEC(fpusegm) + pushl $0; TRAP(T_FPOPFLT) +IDTVEC(tss) + TRAP(T_TSSFLT) + /*PANIC("TSS not valid");*/ +IDTVEC(missing) + TRAP(T_SEGNPFLT) +IDTVEC(stk) + TRAP(T_STKFLT) +IDTVEC(prot) + TRAP(T_PROTFLT) +IDTVEC(page) + TRAP(T_PAGEFLT) +IDTVEC(rsvd) + pushl $0; TRAP(T_RESERVED) +IDTVEC(fpu) +#ifdef NPX + /* + * Handle like an interrupt so that we can call npxintr to clear the + * error. It would be better to handle npx interrupts as traps but + * this is difficult for nested interrupts. + */ + pushl $0 /* dummy error code */ + pushl $T_ASTFLT + pushal + nop /* silly, the bug is for popal and it only + * bites when the next instruction has a + * complicated address mode */ + pushl %ds + pushl %es /* now the stack frame is a trap frame */ + movl $KDSEL,%eax + movl %ax,%ds + movl %ax,%es + pushl _cpl + pushl $0 /* dummy unit to finish building intr frame */ + incl _cnt+V_TRAP + call _npxintr + jmp doreti +#else + pushl $0; TRAP(T_ARITHTRAP) +#endif + /* 17 - 31 reserved for future exp */ +IDTVEC(rsvd0) + pushl $0; TRAP(17) +IDTVEC(rsvd1) + pushl $0; TRAP(18) +IDTVEC(rsvd2) + pushl $0; TRAP(19) +IDTVEC(rsvd3) + pushl $0; TRAP(20) +IDTVEC(rsvd4) + pushl $0; TRAP(21) +IDTVEC(rsvd5) + pushl $0; TRAP(22) +IDTVEC(rsvd6) + pushl $0; TRAP(23) +IDTVEC(rsvd7) + pushl $0; TRAP(24) +IDTVEC(rsvd8) + pushl $0; TRAP(25) +IDTVEC(rsvd9) + pushl $0; TRAP(26) +IDTVEC(rsvd10) + pushl $0; TRAP(27) +IDTVEC(rsvd11) + pushl $0; TRAP(28) +IDTVEC(rsvd12) + pushl $0; TRAP(29) +IDTVEC(rsvd13) + pushl $0; TRAP(30) +IDTVEC(rsvd14) + pushl $0; TRAP(31) + + SUPERALIGN_TEXT +alltraps: + pushal + nop + pushl %ds + pushl %es + movl $KDSEL,%eax + movl %ax,%ds + movl %ax,%es +calltrap: + incl _cnt+V_TRAP + call _trap + /* + * Return through doreti to handle ASTs. Have to change trap frame + * to interrupt frame. + */ + movl $T_ASTFLT,4+4+32(%esp) /* new trap type (err code not used) */ + pushl _cpl + pushl $0 /* dummy unit */ + jmp doreti + +#ifdef KGDB +/* + * This code checks for a kgdb trap, then falls through + * to the regular trap code. + */ + ALIGN_TEXT +bpttraps: + pushal + nop + pushl %es + pushl %ds + movl $KDSEL,%eax + movl %ax,%ds + movl %ax,%es + testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp) + # non-kernel mode? + jne calltrap # yes + call _kgdb_trap_glue + jmp calltrap +#endif + +/* + * Call gate entry for syscall + */ + + SUPERALIGN_TEXT +IDTVEC(syscall) + pushfl # only for stupid carry bit and more stupid wait3 cc kludge + # XXX - also for direction flag (bzero, etc. clear it) + pushal # only need eax,ecx,edx - trap resaves others + nop + movl $KDSEL,%eax # switch to kernel segments + movl %ax,%ds + movl %ax,%es + incl _cnt+V_SYSCALL # kml 3/25/93 + call _syscall + /* + * Return through doreti to handle ASTs. Have to change syscall frame + * to interrupt frame. + * + * XXX - we should have set up the frame earlier to avoid the + * following popal/pushal (not much can be done to avoid shuffling + * the flags). Consistent frames would simplify things all over. + */ + movl 32+0(%esp),%eax /* old flags, shuffle to above cs:eip */ + movl 32+4(%esp),%ebx /* `int' frame should have been ef, eip, cs */ + movl 32+8(%esp),%ecx + movl %ebx,32+0(%esp) + movl %ecx,32+4(%esp) + movl %eax,32+8(%esp) + popal + nop + pushl $0 /* dummy error code */ + pushl $T_ASTFLT + pushal + nop + movl __udatasel,%eax /* switch back to user segments */ + push %eax /* XXX - better to preserve originals? */ + push %eax + pushl _cpl + pushl $0 + jmp doreti + +ENTRY(htonl) +ENTRY(ntohl) + movl 4(%esp),%eax +#ifdef i486 + /* XXX */ + /* Since Gas 1.38 does not grok bswap this has been coded as the + * equivalent bytes. This can be changed back to bswap when we + * upgrade to a newer version of Gas */ + /* bswap %eax */ + .byte 0x0f + .byte 0xc8 +#else + xchgb %al,%ah + roll $16,%eax + xchgb %al,%ah +#endif + ret + +ENTRY(htons) +ENTRY(ntohs) + movzwl 4(%esp),%eax + xchgb %al,%ah + ret + +#ifdef SHOW_A_LOT + +/* + * 'show_bits' was too big when defined as a macro. The line length for some + * enclosing macro was too big for gas. Perhaps the code would have blown + * the cache anyway. + */ + + ALIGN_TEXT +show_bits: + pushl %eax + SHOW_BIT(0) + SHOW_BIT(1) + SHOW_BIT(2) + SHOW_BIT(3) + SHOW_BIT(4) + SHOW_BIT(5) + SHOW_BIT(6) + SHOW_BIT(7) + SHOW_BIT(8) + SHOW_BIT(9) + SHOW_BIT(10) + SHOW_BIT(11) + SHOW_BIT(12) + SHOW_BIT(13) + SHOW_BIT(14) + SHOW_BIT(15) + popl %eax + ret + + .data +bit_colors: + .byte GREEN,RED,0,0 + .text + +#endif /* SHOW_A_LOT */ + +#include "i386/isa/vector.s" +#include "i386/isa/icu.s" diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c new file mode 100644 index 000000000000..f0351a7ddf9e --- /dev/null +++ b/sys/amd64/amd64/machdep.c @@ -0,0 +1,1131 @@ +/*- + * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. + * Copyright (c) 1992 Terrence R. Lambert. + * 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. + * + * @(#)machdep.c 7.4 (Berkeley) 6/3/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 5 00158 + * -------------------- ----- ---------------------- + * + * 15 Aug 92 William Jolitz Large memory bug + * 15 Aug 92 Terry Lambert Fixed CMOS RAM size bug + * 25 Mar 93 Sean Eric Fagan Added #ifdef HZ around microtime for + * the new microtime.s routine + * 08 Apr 93 Andrew Herbert Fixes for kmem_alloc panics + * 20 Apr 93 Bruce Evans New npx-0.5 code + * 25 Apr 93 Bruce Evans New intr-0.1 code + */ +static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/i386/RCS/machdep.c,v 1.2 92/01/21 14:22:09 william Exp Locker: root $"; + + +#include <stddef.h> +#include "param.h" +#include "systm.h" +#include "signalvar.h" +#include "kernel.h" +#include "proc.h" +#include "user.h" +#include "buf.h" +#include "reboot.h" +#include "conf.h" +#include "file.h" +#include "callout.h" +#include "malloc.h" +#include "mbuf.h" +#include "msgbuf.h" +#include "net/netisr.h" + +#include "vm/vm.h" +#include "vm/vm_kern.h" +#include "vm/vm_page.h" + +extern vm_offset_t avail_end; + +#include "machine/cpu.h" +#include "machine/reg.h" +#include "machine/psl.h" +#include "machine/specialreg.h" +#include "i386/isa/rtc.h" + + +#define EXPECT_BASEMEM 640 /* The expected base memory*/ +#define INFORM_WAIT 1 /* Set to pause berfore crash in weird cases*/ + +/* + * 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; /* set when safe to use msgbuf */ +extern int freebufspace; + +/* + * Machine-dependent startup code + */ +int boothowto = 0, Maxmem = 0; +long dumplo; +int physmem, maxmem; +extern int bootdev; +#ifdef SMALL +extern int forcemaxmem; +#endif +int biosmem; + +extern cyloffset; + +cpu_startup() +{ + register int unixsize; + register unsigned i; + register struct pte *pte; + int mapaddr, j; + register caddr_t v; + int maxbufs, base, residual; + extern long Usrptsize; + vm_offset_t minaddr, maxaddr; + vm_size_t size; + int firstaddr; + + /* + * Initialize error message buffer (at end of core). + */ + + /* avail_end was pre-decremented in pmap_bootstrap to compensate */ + for (i = 0; i < btoc(sizeof (struct msgbuf)); i++) + pmap_enter(pmap_kernel(), msgbufp, avail_end + i * NBPG, + VM_PROT_ALL, TRUE); + msgbufmapped = 1; + +#ifdef KDB + kdb_init(); /* startup kernel debugger */ +#endif + /* + * Good {morning,afternoon,evening,night}. + */ + /*printf(version); + printf("real mem = %d\n", ctob(physmem));*/ + + /* + * 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. + * As pages of memory are allocated and cleared, + * "firstaddr" is incremented. + * An index into the kernel page table corresponding to the + * virtual memory address maintained in "v" is kept in "mapaddr". + */ + + /* + * Make two passes. The first pass calculates how much memory is + * needed and allocates it. The second pass assigns virtual + * addresses to the various data structures. + */ + firstaddr = 0; +again: + v = (caddr_t)firstaddr; + +#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))) + valloc(callout, struct callout, ncallout); +#ifdef SYSVSHM + valloc(shmsegs, struct shmid_ds, shminfo.shmmni); +#endif + /* + * Determine how many buffers to allocate. + * Use 10% of memory for the first 2 Meg, 5% of the remaining + * memory. Insure a minimum of 16 buffers. + * We allocate 1/2 as many swap buffer headers as file i/o buffers. + */ + if (bufpages == 0) + if (physmem < (2 * 1024 * 1024)) + bufpages = physmem / 10 / CLSIZE; + else + bufpages = ((2 * 1024 * 1024 + physmem) / 20) / CLSIZE; + /* + * 15 Aug 92 William Jolitz bufpages fix for too large + */ + bufpages = min( NKMEMCLUSTERS*2/5, bufpages); + + if (nbuf == 0) { + nbuf = bufpages / 2; + if (nbuf < 16) + nbuf = 16; + } + freebufspace = bufpages * NBPG; + 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); + + /* + * End of first pass, size has been calculated so allocate memory + */ + if (firstaddr == 0) { + size = (vm_size_t)(v - firstaddr); + firstaddr = (int)kmem_alloc(kernel_map, round_page(size)); + if (firstaddr == 0) + panic("startup: no room for tables"); + goto again; + } + /* + * End of second pass, addresses have been assigned + */ + if ((vm_size_t)(v - firstaddr) != size) + panic("startup: table size inconsistency"); + /* + * Allocate a submap for buffer space allocations. + */ + buffer_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, + bufpages*NBPG, 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]; + + /*printf("avail mem = %d\n", ptoa(vm_page_free_count));*/ + + /* + * 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(); +} + +#ifdef PGINPROF +/* + * Return the difference (in microseconds) + * between the current time and a previous + * time as represented by the arguments. + * If there is a pending clock interrupt + * which has not been serviced due to high + * ipl, return error code. + */ +/*ARGSUSED*/ +vmtime(otime, olbolt, oicr) + register int otime, olbolt, oicr; +{ + + return (((time.tv_sec-otime)*60 + lbolt-olbolt)*16667); +} +#endif + +struct sigframe { + int sf_signum; + int sf_code; + struct sigcontext *sf_scp; + sig_t sf_handler; + int sf_eax; + int sf_edx; + int sf_ecx; + struct sigcontext sf_sc; +} ; + +extern int kstack[]; + +/* + * Send an interrupt to process. + * + * Stack is set up to allow sigcode stored + * in u. to call routine, followed by kcall + * to sigreturn routine below. After sigreturn + * resets the signal mask, the stack, and the + * frame pointer, it returns to the user + * specified pc, psl. + */ +void +sendsig(catcher, sig, mask, code) + sig_t catcher; + int sig, mask; + unsigned code; +{ + register struct proc *p = curproc; + register int *regs; + register struct sigframe *fp; + struct sigacts *ps = p->p_sigacts; + int oonstack, frmtrap; + + regs = p->p_regs; + oonstack = ps->ps_onstack; + frmtrap = curpcb->pcb_flags & FM_TRAP; + /* + * Allocate and validate space for the signal handler + * context. Note that if the stack is in P0 space, the + * call to grow() is a nop, and the useracc() check + * will fail if the process has not already allocated + * the space with a `brk'. + */ + if (!ps->ps_onstack && (ps->ps_sigonstack & sigmask(sig))) { + fp = (struct sigframe *)(ps->ps_sigsp + - sizeof(struct sigframe)); + ps->ps_onstack = 1; + } else { + if (frmtrap) + fp = (struct sigframe *)(regs[tESP] + - sizeof(struct sigframe)); + else + fp = (struct sigframe *)(regs[sESP] + - sizeof(struct sigframe)); + } + + if ((unsigned)fp <= (unsigned)p->p_vmspace->vm_maxsaddr + MAXSSIZ - ctob(p->p_vmspace->vm_ssize)) + (void)grow(p, (unsigned)fp); + + if (useracc((caddr_t)fp, sizeof (struct sigframe), B_WRITE) == 0) { + /* + * 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. + */ + fp->sf_signum = sig; + fp->sf_code = code; + fp->sf_scp = &fp->sf_sc; + fp->sf_handler = catcher; + + /* save scratch registers */ + if(frmtrap) { + fp->sf_eax = regs[tEAX]; + fp->sf_edx = regs[tEDX]; + fp->sf_ecx = regs[tECX]; + } else { + fp->sf_eax = regs[sEAX]; + fp->sf_edx = regs[sEDX]; + fp->sf_ecx = regs[sECX]; + } + /* + * Build the signal context to be used by sigreturn. + */ + fp->sf_sc.sc_onstack = oonstack; + fp->sf_sc.sc_mask = mask; + if(frmtrap) { + fp->sf_sc.sc_sp = regs[tESP]; + fp->sf_sc.sc_fp = regs[tEBP]; + fp->sf_sc.sc_pc = regs[tEIP]; + fp->sf_sc.sc_ps = regs[tEFLAGS]; + regs[tESP] = (int)fp; + regs[tEIP] = (int)((struct pcb *)kstack)->pcb_sigc; + } else { + fp->sf_sc.sc_sp = regs[sESP]; + fp->sf_sc.sc_fp = regs[sEBP]; + fp->sf_sc.sc_pc = regs[sEIP]; + fp->sf_sc.sc_ps = regs[sEFLAGS]; + regs[sESP] = (int)fp; + regs[sEIP] = (int)((struct pcb *)kstack)->pcb_sigc; + } +} + +/* + * 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. + */ +sigreturn(p, uap, retval) + struct proc *p; + struct args { + struct sigcontext *sigcntxp; + } *uap; + int *retval; +{ + register struct sigcontext *scp; + register struct sigframe *fp; + register int *regs = p->p_regs; + + + /* + * (XXX old comment) regs[sESP] points to the return address. + * The user scp pointer is above that. + * The return address is faked in the signal trampoline code + * for consistency. + */ + scp = uap->sigcntxp; + fp = (struct sigframe *) + ((caddr_t)scp - offsetof(struct sigframe, sf_sc)); + + if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0) + return(EINVAL); + + /* restore scratch registers */ + regs[sEAX] = fp->sf_eax ; + regs[sEDX] = fp->sf_edx ; + regs[sECX] = fp->sf_ecx ; + + if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0) + return(EINVAL); +#ifdef notyet + if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO) { + return(EINVAL); + } +#endif + p->p_sigacts->ps_onstack = scp->sc_onstack & 01; + p->p_sigmask = scp->sc_mask &~ + (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP)); + regs[sEBP] = scp->sc_fp; + regs[sESP] = scp->sc_sp; + regs[sEIP] = scp->sc_pc; + regs[sEFLAGS] = scp->sc_ps; + return(EJUSTRETURN); +} + +int waittime = -1; +struct pcb dumppcb; + +boot(arghowto) + int arghowto; +{ + register long dummy; /* r12 is reserved */ + register int howto; /* r11 == how to boot */ + register int devtype; /* r10 == major of root dev */ + extern char *panicstr; + extern int cold; + int nomsg = 1; + + if(cold) { + printf("hit reset please"); + for(;;); + } + howto = arghowto; + if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) { + register struct buf *bp; + int iter, nbusy; + + waittime = 0; + (void) splnet(); + /* + * Release inodes held by texts before update. + */ + if (panicstr == 0) + vnode_pager_umount(NULL); + sync((struct sigcontext *)0); + + for (iter = 0; iter < 20; iter++) { + nbusy = 0; + for (bp = &buf[nbuf]; --bp >= buf; ) + if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY) + nbusy++; + if (nbusy == 0) + break; + if (nomsg) { + printf("updating disks before rebooting... "); + nomsg = 0; + } + /* printf("%d ", nbusy); */ + DELAY(40000 * iter); + } + if (nbusy) + printf(" failed!\n"); + else if (nomsg == 0) + printf("succeded.\n"); + DELAY(10000); /* wait for printf to finish */ + } + splhigh(); + devtype = major(rootdev); + if (howto&RB_HALT) { + pg("\nThe operating system has halted. Please press any key to reboot.\n\n"); + } else { + if (howto & RB_DUMP) { + savectx(&dumppcb, 0); + dumppcb.pcb_ptd = rcr3(); + dumpsys(); + /*NOTREACHED*/ + } + } +#ifdef lint + dummy = 0; dummy = dummy; + printf("howto %d, devtype %d\n", arghowto, devtype); +#endif + cpu_reset(); + for(;;) ; + /*NOTREACHED*/ +} + +int dumpmag = 0x8fca0101; /* magic number for savecore */ +int dumpsize = 0; /* also for savecore */ +/* + * 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() +{ + + if (dumpdev == NODEV) + return; + if ((minor(dumpdev)&07) != 1) + return; + printf("\nThe operating system is saving a copy of RAM memory to device %x, offset %d\n\ +(hit any key to abort): [ amount left to save (MB) ] ", dumpdev, dumplo); + dumpsize = physmem; + switch ((*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; + + case EINTR: + printf("-- aborted from console\n"); + break; + + default: + printf(" succeeded\n"); + break; + } + printf("system rebooting.\n\n"); + DELAY(10000); +} + +#ifdef HZ +/* + * If HZ is defined we use this code, otherwise the code in + * /sys/i386/i386/microtime.s is used. The othercode only works + * for HZ=100. + */ +microtime(tvp) + register struct timeval *tvp; +{ + int s = splhigh(); + + *tvp = time; + tvp->tv_usec += tick; + while (tvp->tv_usec > 1000000) { + tvp->tv_sec++; + tvp->tv_usec -= 1000000; + } + splx(s); +} +#endif /* HZ */ + +physstrat(bp, strat, prio) + struct buf *bp; + int (*strat)(), prio; +{ + register int s; + caddr_t baddr; + + /* + * vmapbuf clobbers b_addr so we must remember it so that it + * can be restored after vunmapbuf. This is truely rude, we + * should really be storing this in a field in the buf struct + * but none are available and I didn't want to add one at + * this time. Note that b_addr for dirty page pushes is + * restored in vunmapbuf. (ugh!) + */ + baddr = bp->b_un.b_addr; + vmapbuf(bp); + (*strat)(bp); + /* pageout daemon doesn't wait for pushed pages */ + if (bp->b_flags & B_DIRTY) + return; + s = splbio(); + while ((bp->b_flags & B_DONE) == 0) + sleep((caddr_t)bp, prio); + splx(s); + vunmapbuf(bp); + bp->b_un.b_addr = baddr; +} + +initcpu() +{ +} + +/* + * Clear registers on exec + */ +setregs(p, entry) + struct proc *p; + u_long entry; +{ + + p->p_regs[sEBP] = 0; /* bottom of the fp chain */ + p->p_regs[sEIP] = entry; + + p->p_addr->u_pcb.pcb_flags = 0; /* no fp at all */ + load_cr0(rcr0() | CR0_TS); /* start emulating */ +#ifdef NPX + npxinit(__INITIAL_NPXCW__); +#endif +} + +/* + * Initialize 386 and configure to run kernel + */ + +/* + * Initialize segments & interrupt table + */ + + +#define GNULL_SEL 0 /* Null Descriptor */ +#define GCODE_SEL 1 /* Kernel Code Descriptor */ +#define GDATA_SEL 2 /* Kernel Data Descriptor */ +#define GLDT_SEL 3 /* LDT - eventually one per process */ +#define GTGATE_SEL 4 /* Process task switch gate */ +#define GPANIC_SEL 5 /* Task state to consider panic from */ +#define GPROC0_SEL 6 /* Task state process slot zero and up */ +#define NGDT GPROC0_SEL+1 + +union descriptor gdt[GPROC0_SEL+1]; + +/* interrupt descriptor table */ +struct gate_descriptor idt[NIDT]; + +/* local descriptor table */ +union descriptor ldt[5]; +#define LSYS5CALLS_SEL 0 /* forced by intel BCS */ +#define LSYS5SIGR_SEL 1 + +#define L43BSDCALLS_SEL 2 /* notyet */ +#define LUCODE_SEL 3 +#define LUDATA_SEL 4 +/* seperate stack, es,fs,gs sels ? */ +/* #define LPOSIXCALLS_SEL 5 /* notyet */ + +struct i386tss tss, panic_tss; + +extern struct user *proc0paddr; + +/* software prototypes -- in more palitable form */ +struct soft_segment_descriptor gdt_segs[] = { + /* Null Descriptor */ +{ 0x0, /* segment base address */ + 0x0, /* length - all address space */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0,0, + 0, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Code Descriptor for kernel */ +{ 0x0, /* segment base address */ + 0xfffff, /* length - all address space */ + SDT_MEMERA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 1, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, + /* Data Descriptor for kernel */ +{ 0x0, /* segment base address */ + 0xfffff, /* length - all address space */ + SDT_MEMRWA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 1, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, + /* LDT Descriptor */ +{ (int) ldt, /* segment base address */ + sizeof(ldt)-1, /* length - all address space */ + SDT_SYSLDT, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 0, /* unused - default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Null Descriptor - Placeholder */ +{ 0x0, /* segment base address */ + 0x0, /* length - all address space */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0,0, + 0, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Panic Tss Descriptor */ +{ (int) &panic_tss, /* segment base address */ + sizeof(tss)-1, /* length - all address space */ + SDT_SYS386TSS, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 0, /* unused - default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Proc 0 Tss Descriptor */ +{ (int) kstack, /* segment base address */ + sizeof(tss)-1, /* length - all address space */ + SDT_SYS386TSS, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 0, /* unused - default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }}; + +struct soft_segment_descriptor ldt_segs[] = { + /* Null Descriptor - overwritten by call gate */ +{ 0x0, /* segment base address */ + 0x0, /* length - all address space */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0,0, + 0, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Null Descriptor - overwritten by call gate */ +{ 0x0, /* segment base address */ + 0x0, /* length - all address space */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0,0, + 0, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Null Descriptor - overwritten by call gate */ +{ 0x0, /* segment base address */ + 0x0, /* length - all address space */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0,0, + 0, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Code Descriptor for user */ +{ 0x0, /* segment base address */ + 0xfffff, /* length - all address space */ + SDT_MEMERA, /* segment type */ + SEL_UPL, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 1, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, + /* Data Descriptor for user */ +{ 0x0, /* segment base address */ + 0xfffff, /* length - all address space */ + SDT_MEMRWA, /* segment type */ + SEL_UPL, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 1, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ } }; + +setidt(idx, func, typ, dpl) char *func; { + struct gate_descriptor *ip = idt + idx; + + ip->gd_looffset = (int)func; + ip->gd_selector = 8; + ip->gd_stkcpy = 0; + ip->gd_xx = 0; + ip->gd_type = typ; + ip->gd_dpl = dpl; + ip->gd_p = 1; + ip->gd_hioffset = ((int)func)>>16 ; +} + +#define IDTVEC(name) __CONCAT(X, name) +extern IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl), + IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm), + IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), + IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0), + IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4), + IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8), + IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12), + IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(rsvd14), IDTVEC(syscall); + +int lcr0(), lcr3(), rcr0(), rcr2(); +int _udatasel, _ucodesel, _gsel_tss; + +init386(first) +{ + extern ssdtosd(), lgdt(), lidt(), lldt(), etext; + int x, *pi; + unsigned biosbasemem, biosextmem; + struct gate_descriptor *gdp; + extern int sigcode,szsigcode; + /* table descriptors - used to load tables by microp */ + struct region_descriptor r_gdt, r_idt; + int pagesinbase, pagesinext; + + + proc0.p_addr = proc0paddr; + + /* + * Initialize the console before we print anything out. + */ + + cninit (KERNBASE+0xa0000); + + /* make gdt memory segments */ + gdt_segs[GCODE_SEL].ssd_limit = btoc((int) &etext + NBPG); + for (x=0; x < NGDT; x++) ssdtosd(gdt_segs+x, gdt+x); + /* make ldt memory segments */ + ldt_segs[LUCODE_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS); + ldt_segs[LUDATA_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS); + /* Note. eventually want private ldts per process */ + for (x=0; x < 5; x++) ssdtosd(ldt_segs+x, ldt+x); + + /* exceptions */ + setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL); + setidt(1, &IDTVEC(dbg), SDT_SYS386TGT, SEL_KPL); + setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL); + setidt(3, &IDTVEC(bpt), SDT_SYS386TGT, SEL_UPL); + setidt(4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_KPL); + setidt(5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL); + setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL); + setidt(7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL); + setidt(8, &IDTVEC(dble), SDT_SYS386TGT, SEL_KPL); + setidt(9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL); + setidt(10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL); + setidt(11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL); + setidt(12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL); + setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL); + setidt(14, &IDTVEC(page), SDT_SYS386TGT, SEL_KPL); + setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL); + setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL); + setidt(17, &IDTVEC(rsvd0), SDT_SYS386TGT, SEL_KPL); + setidt(18, &IDTVEC(rsvd1), SDT_SYS386TGT, SEL_KPL); + setidt(19, &IDTVEC(rsvd2), SDT_SYS386TGT, SEL_KPL); + setidt(20, &IDTVEC(rsvd3), SDT_SYS386TGT, SEL_KPL); + setidt(21, &IDTVEC(rsvd4), SDT_SYS386TGT, SEL_KPL); + setidt(22, &IDTVEC(rsvd5), SDT_SYS386TGT, SEL_KPL); + setidt(23, &IDTVEC(rsvd6), SDT_SYS386TGT, SEL_KPL); + setidt(24, &IDTVEC(rsvd7), SDT_SYS386TGT, SEL_KPL); + setidt(25, &IDTVEC(rsvd8), SDT_SYS386TGT, SEL_KPL); + setidt(26, &IDTVEC(rsvd9), SDT_SYS386TGT, SEL_KPL); + setidt(27, &IDTVEC(rsvd10), SDT_SYS386TGT, SEL_KPL); + setidt(28, &IDTVEC(rsvd11), SDT_SYS386TGT, SEL_KPL); + setidt(29, &IDTVEC(rsvd12), SDT_SYS386TGT, SEL_KPL); + setidt(30, &IDTVEC(rsvd13), SDT_SYS386TGT, SEL_KPL); + setidt(31, &IDTVEC(rsvd14), SDT_SYS386TGT, SEL_KPL); + +#include "isa.h" +#if NISA >0 + isa_defaultirq(); +#endif + + r_gdt.rd_limit = sizeof(gdt)-1; + r_gdt.rd_base = (int) gdt; + lgdt(&r_gdt); + r_idt.rd_limit = sizeof(idt)-1; + r_idt.rd_base = (int) idt; + lidt(&r_idt); + lldt(GSEL(GLDT_SEL, SEL_KPL)); + +#include "ddb.h" +#if NDDB > 0 + kdb_init(); + if (boothowto & RB_KDB) + Debugger(); +#endif + + /* Use BIOS values stored in RTC CMOS RAM, since probing + * breaks certain 386 AT relics. + */ + biosbasemem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8); + biosextmem = rtcin(RTC_EXTLO)+ (rtcin(RTC_EXTHI)<<8); +/*printf("bios base %d ext %d ", biosbasemem, biosextmem);*/ + + /* + * 15 Aug 92 Terry Lambert The real fix for the CMOS bug + */ + if( biosbasemem != EXPECT_BASEMEM) { + printf( "Warning: Base memory %dK, assuming %dK\n", biosbasemem, EXPECT_BASEMEM); + biosbasemem = EXPECT_BASEMEM; /* assume base*/ + } + + if( biosextmem > 65536) { + printf( "Warning: Extended memory %dK(>64M), assuming 0K\n", biosextmem); + biosextmem = 0; /* assume none*/ + } + + /* + * Go into normal calculation; Note that we try to run in 640K, and + * that invalid CMOS values of non 0xffff are no longer a cause of + * ptdi problems. I have found a gutted kernel can run in 640K. + */ + pagesinbase = 640/4 - first/NBPG; + pagesinext = biosextmem/4; + /* use greater of either base or extended memory. do this + * until I reinstitue discontiguous allocation of vm_page + * array. + */ + if (pagesinbase > pagesinext) + Maxmem = 640/4; + else { + Maxmem = pagesinext + 0x100000/NBPG; + first = 0x100000; /* skip hole */ + } + + /* This used to explode, since Maxmem used to be 0 for bas CMOS*/ + maxmem = Maxmem - 1; /* highest page of usable memory */ + physmem = maxmem; /* number of pages of physmem addr space */ +/*printf("using first 0x%x to 0x%x\n ", first, maxmem*NBPG);*/ + if (maxmem < 2048/4) { + printf("Too little RAM memory. Warning, running in degraded mode.\n"); +#ifdef INFORM_WAIT + /* + * People with less than 2 Meg have to hit return; this way + * we see the messages and can tell them why they blow up later. + * If they get working well enough to recompile, they can unset + * the flag; otherwise, it's a toy and they have to lump it. + */ + getchar(); /* kernel getchar in /sys/i386/isa/pccons.c*/ +#endif /* !INFORM_WAIT*/ + } + /* + * End of CMOS bux fix + */ + + /* call pmap initialization to make new kernel address space */ + pmap_bootstrap (first, 0); + /* now running on new page tables, configured,and u/iom is accessible */ + + /* make a initial tss so microp can get interrupt stack on syscall! */ + proc0.p_addr->u_pcb.pcb_tss.tss_esp0 = (int) kstack + UPAGES*NBPG; + proc0.p_addr->u_pcb.pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ; + _gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); + ltr(_gsel_tss); + + /* make a call gate to reenter kernel with */ + gdp = &ldt[LSYS5CALLS_SEL].gd; + + x = (int) &IDTVEC(syscall); + gdp->gd_looffset = x++; + gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL); + gdp->gd_stkcpy = 0; + gdp->gd_type = SDT_SYS386CGT; + gdp->gd_dpl = SEL_UPL; + gdp->gd_p = 1; + gdp->gd_hioffset = ((int) &IDTVEC(syscall)) >>16; + + /* transfer to user mode */ + + _ucodesel = LSEL(LUCODE_SEL, SEL_UPL); + _udatasel = LSEL(LUDATA_SEL, SEL_UPL); + + /* setup proc 0's pcb */ + bcopy(&sigcode, proc0.p_addr->u_pcb.pcb_sigc, szsigcode); + proc0.p_addr->u_pcb.pcb_flags = 0; + proc0.p_addr->u_pcb.pcb_ptd = IdlePTD; +} + +extern struct pte *CMAP1, *CMAP2; +extern caddr_t CADDR1, CADDR2; +/* + * zero out physical memory + * specified in relocation units (NBPG bytes) + */ +clearseg(n) { + + *(int *)CMAP2 = PG_V | PG_KW | ctob(n); + load_cr3(rcr3()); + bzero(CADDR2,NBPG); + *(int *) CADDR2 = 0; +} + +/* + * copy a page of physical memory + * specified in relocation units (NBPG bytes) + */ +copyseg(frm, n) { + + *(int *)CMAP2 = PG_V | PG_KW | ctob(n); + load_cr3(rcr3()); + bcopy((void *)frm, (void *)CADDR2, NBPG); +} + +/* + * copy a page of physical memory + * specified in relocation units (NBPG bytes) + */ +physcopyseg(frm, to) { + + *(int *)CMAP1 = PG_V | PG_KW | ctob(frm); + *(int *)CMAP2 = PG_V | PG_KW | ctob(to); + load_cr3(rcr3()); + bcopy(CADDR1, CADDR2, NBPG); +} + +/*aston() { + schednetisr(NETISR_AST); +}*/ + +setsoftclock() { + schednetisr(NETISR_SCLK); +} + +/* + * insert an element into a queue + */ +#undef insque +_insque(element, head) + register struct prochd *element, *head; +{ + element->ph_link = head->ph_link; + head->ph_link = (struct proc *)element; + element->ph_rlink = (struct proc *)head; + ((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element; +} + +/* + * remove an element from a queue + */ +#undef remque +_remque(element) + register struct prochd *element; +{ + ((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink; + ((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link; + element->ph_rlink = (struct proc *)0; +} + +vmunaccess() {} + +/* + * Below written in C to allow access to debugging code + */ +copyinstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength; + void *toaddr, *fromaddr; { + int c,tally; + + tally = 0; + while (maxlength--) { + c = fubyte(fromaddr++); + if (c == -1) { + if(lencopied) *lencopied = tally; + return(EFAULT); + } + tally++; + *(char *)toaddr++ = (char) c; + if (c == 0){ + if(lencopied) *lencopied = (u_int)tally; + return(0); + } + } + if(lencopied) *lencopied = (u_int)tally; + return(ENAMETOOLONG); +} + +copyoutstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength; + void *fromaddr, *toaddr; { + int c; + int tally; + + tally = 0; + while (maxlength--) { + c = subyte(toaddr++, *(char *)fromaddr); + if (c == -1) return(EFAULT); + tally++; + if (*(char *)fromaddr++ == 0){ + if(lencopied) *lencopied = tally; + return(0); + } + } + if(lencopied) *lencopied = tally; + return(ENAMETOOLONG); +} + +copystr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength; + void *fromaddr, *toaddr; { + u_int tally; + + tally = 0; + while (maxlength--) { + *(u_char *)toaddr = *(u_char *)fromaddr++; + tally++; + if (*(u_char *)toaddr++ == 0) { + if(lencopied) *lencopied = tally; + return(0); + } + } + if(lencopied) *lencopied = tally; + return(ENAMETOOLONG); +} diff --git a/sys/amd64/amd64/mem.c b/sys/amd64/amd64/mem.c new file mode 100644 index 000000000000..650e21eb509c --- /dev/null +++ b/sys/amd64/amd64/mem.c @@ -0,0 +1,191 @@ +/*- + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1986, 1990 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 code 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. + * + * from: Utah $Hdr: mem.c 1.13 89/10/08$ + * @(#)mem.c 7.2 (Berkeley) 5/9/91 + */ + +/* + * Memory special file + */ + +#include "param.h" +#include "conf.h" +#include "buf.h" +#include "systm.h" +#include "uio.h" +#include "malloc.h" + +#include "machine/cpu.h" + +#include "vm/vm_param.h" +#include "vm/lock.h" +#include "vm/vm_statistics.h" +#include "vm/pmap.h" +#include "vm/vm_prot.h" + +extern char *vmmap; /* poor name! */ +/*ARGSUSED*/ +mmrw(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + register int o; + register u_int c, v; + register struct iovec *iov; + int error = 0; + caddr_t zbuf = NULL; + + 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; + pmap_enter(pmap_kernel(), vmmap, v, + uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE, + TRUE); + o = (int)uio->uio_offset & PGOFSET; + c = (u_int)(NBPG - ((int)iov->iov_base & PGOFSET)); + c = MIN(c, (u_int)(NBPG - o)); + c = MIN(c, (u_int)iov->iov_len); + error = uiomove((caddr_t)&vmmap[o], (int)c, uio); + pmap_remove(pmap_kernel(), vmmap, &vmmap[NBPG]); + continue; + +/* minor device 1 is kernel memory */ + case 1: + c = iov->iov_len; + if (!kernacc((caddr_t)uio->uio_offset, c, + uio->uio_rw == UIO_READ ? B_READ : B_WRITE)) + return(EFAULT); + error = uiomove((caddr_t)uio->uio_offset, (int)c, uio); + continue; + +/* minor device 2 is EOF/RATHOLE */ + case 2: + if (uio->uio_rw == UIO_READ) + return (0); + c = iov->iov_len; + break; + +/* 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 (zbuf == NULL) { + zbuf = (caddr_t) + malloc(CLBYTES, M_TEMP, M_WAITOK); + bzero(zbuf, CLBYTES); + } + c = MIN(iov->iov_len, CLBYTES); + error = uiomove(zbuf, (int)c, uio); + continue; + +#ifdef notyet +/* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate + i/o device address bus, different than memory bus. Semantics here are + very different than ordinary read/write, as if iov_len is a multiple + an implied string move from a single port will be done. Note that lseek + must be used to set the port number reliably. */ + case 14: + if (iov->iov_len == 1) { + u_char tmp; + tmp = inb(uio->uio_offset); + error = uiomove (&tmp, iov->iov_len, uio); + } else { + if (!useracc((caddr_t)iov->iov_base, + iov->iov_len, uio->uio_rw)) + return (EFAULT); + insb(uio->uio_offset, iov->iov_base, + iov->iov_len); + } + break; + case 15: + if (iov->iov_len == sizeof (short)) { + u_short tmp; + tmp = inw(uio->uio_offset); + error = uiomove (&tmp, iov->iov_len, uio); + } else { + if (!useracc((caddr_t)iov->iov_base, + iov->iov_len, uio->uio_rw)) + return (EFAULT); + insw(uio->uio_offset, iov->iov_base, + iov->iov_len/ sizeof (short)); + } + break; + case 16: + if (iov->iov_len == sizeof (long)) { + u_long tmp; + tmp = inl(uio->uio_offset); + error = uiomove (&tmp, iov->iov_len, uio); + } else { + if (!useracc((caddr_t)iov->iov_base, + iov->iov_len, uio->uio_rw)) + return (EFAULT); + insl(uio->uio_offset, iov->iov_base, + iov->iov_len/ sizeof (long)); + } + break; +#endif + + default: + return (ENXIO); + } + if (error) + break; + iov->iov_base += c; + iov->iov_len -= c; + uio->uio_offset += c; + uio->uio_resid -= c; + } + if (zbuf) + free(zbuf, M_TEMP); + return (error); +} diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c new file mode 100644 index 000000000000..66c7fec59a8d --- /dev/null +++ b/sys/amd64/amd64/pmap.c @@ -0,0 +1,1728 @@ +/* + * Copyright (c) 1991 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 William Jolitz of UUNET Technologies 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. + * + * @(#)pmap.c 7.7 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00063 + * -------------------- ----- ---------------------- + * + * 28 Nov 1991 Poul-Henning Kamp Speedup processing. + */ +static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/i386/RCS/pmap.c,v 1.3 92/01/21 14:26:44 william Exp Locker: root $"; + +/* + * Derived from hp300 version by Mike Hibler, this version by William + * Jolitz uses a recursive map [a pde points to the page directory] to + * map the page tables using the pagetables themselves. This is done to + * reduce the impact on kernel virtual memory for lots of sparse address + * space, and to reduce the cost of memory to each process. + * + * Derived from: hp300/@(#)pmap.c 7.1 (Berkeley) 12/5/90 + */ + +/* + * Reno i386 version, from Mike Hibler's hp300 version. + */ + +/* + * 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 "param.h" +#include "proc.h" +#include "malloc.h" +#include "user.h" + +#include "vm/vm.h" +#include "vm/vm_kern.h" +#include "vm/vm_page.h" +/*#include "vm/vm_pageout.h"*/ + +#include "i386/isa/isa.h" + +/* + * Allocate various and sundry SYSMAPs used in the days of old VM + * and not yet converted. XXX. + */ +#define BSDVM_COMPAT 1 + +#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 */ +} enter_stats; +struct { + int calls; + int removes; + int pvfirst; + int pvsearch; + int ptinvalid; + int uflushes; + int sflushes; +} remove_stats; + +int debugmap = 0; +int pmapdebug = 0 /* 0xffff */; +#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_CACHE 0x0040 +#define PDB_BITS 0x0080 +#define PDB_COLLECT 0x0100 +#define PDB_PROTECT 0x0200 +#define PDB_PDRTAB 0x0400 +#define PDB_PARANOIA 0x2000 +#define PDB_WIRING 0x4000 +#define PDB_PVDUMP 0x8000 + +int pmapvacflush = 0; +#define PVF_ENTER 0x01 +#define PVF_REMOVE 0x02 +#define PVF_PROTECT 0x04 +#define PVF_TOTAL 0x80 +#endif + +/* + * Get PDEs and PTEs for user/kernel address space + */ +#define pmap_pde(m, v) (&((m)->pm_pdir[((vm_offset_t)(v) >> PD_SHIFT)&1023])) + +#define pmap_pte_pa(pte) (*(int *)(pte) & PG_FRAME) + +#define pmap_pde_v(pte) ((pte)->pd_v) +#define pmap_pte_w(pte) ((pte)->pg_w) +/* #define pmap_pte_ci(pte) ((pte)->pg_ci) */ +#define pmap_pte_m(pte) ((pte)->pg_m) +#define pmap_pte_u(pte) ((pte)->pg_u) +#define pmap_pte_v(pte) ((pte)->pg_v) +#define pmap_pte_set_w(pte, v) ((pte)->pg_w = (v)) +#define pmap_pte_set_prot(pte, v) ((pte)->pg_prot = (v)) + +/* + * Given a map and a machine independent protection code, + * convert to a vax protection code. + */ +#define pte_prot(m, p) (protection_codes[p]) +int protection_codes[8]; + +struct pmap kernel_pmap_store; +pmap_t kernel_pmap; + +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) */ +vm_offset_t vm_first_phys; /* PA of first managed page */ +vm_offset_t vm_last_phys; /* PA just past last managed page */ +int i386pagesperpage; /* PAGE_SIZE / I386_PAGE_SIZE */ +boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */ +char *pmap_attributes; /* reference and modify bits */ + +boolean_t pmap_testbit(); +void pmap_clear_modify(); + +#if BSDVM_COMPAT +#include "msgbuf.h" + +/* + * All those kernel PT submaps that BSD is so fond of + */ +struct pte *CMAP1, *CMAP2, *mmap; +caddr_t CADDR1, CADDR2, vmmap; +struct pte *msgbufmap; +struct msgbuf *msgbufp; +#endif + +/* + * Bootstrap the system enough to run with virtual memory. + * Map the kernel's code and data, and allocate the system page table. + * + * On the I386 this is called after mapping has already been enabled + * and just syncs the pmap module with what has already been done. + * [We can't call it easily with mapping off since the kernel is not + * mapped with PA == VA, hence we would have to relocate every address + * from the linked base (virtual) address 0xFE000000 to the actual + * (physical) address starting relative to 0] + */ +struct pte *pmap_pte(); + +void +pmap_bootstrap(firstaddr, loadaddr) + vm_offset_t firstaddr; + vm_offset_t loadaddr; +{ +#if BSDVM_COMPAT + vm_offset_t va; + struct pte *pte; +#endif + extern vm_offset_t maxmem, physmem; +extern int IdlePTD; + + avail_start = firstaddr; + avail_end = maxmem << PG_SHIFT; + + /* XXX: allow for msgbuf */ + avail_end -= i386_round_page(sizeof(struct msgbuf)); + + mem_size = physmem << PG_SHIFT; + virtual_avail = (vm_offset_t)atdevbase + 0x100000 - 0xa0000 + 10*NBPG; + virtual_end = VM_MAX_KERNEL_ADDRESS; + i386pagesperpage = PAGE_SIZE / I386_PAGE_SIZE; + + /* + * Initialize protection array. + */ + i386_protection_init(); + + /* + * The kernel's pmap is statically allocated so we don't + * have to use pmap_create, which is unlikely to work + * correctly at this part of the boot sequence. + */ + kernel_pmap = &kernel_pmap_store; + +#ifdef notdef + /* + * Create Kernel page directory table and page maps. + * [ currently done in locore. i have wild and crazy ideas -wfj ] + */ + bzero(firstaddr, 4*NBPG); + kernel_pmap->pm_pdir = firstaddr + VM_MIN_KERNEL_ADDRESS; + kernel_pmap->pm_ptab = firstaddr + VM_MIN_KERNEL_ADDRESS + NBPG; + + firstaddr += NBPG; + for (x = i386_btod(VM_MIN_KERNEL_ADDRESS); + x < i386_btod(VM_MIN_KERNEL_ADDRESS)+3; x++) { + struct pde *pde; + pde = kernel_pmap->pm_pdir + x; + *(int *)pde = firstaddr + x*NBPG | PG_V | PG_KW; + } +#else + kernel_pmap->pm_pdir = (pd_entry_t *)(0xfe000000 + IdlePTD); +#endif + + + simple_lock_init(&kernel_pmap->pm_lock); + kernel_pmap->pm_count = 1; + +#if BSDVM_COMPAT + /* + * Allocate all the submaps we need + */ +#define SYSMAP(c, p, v, n) \ + v = (c)va; va += ((n)*I386_PAGE_SIZE); p = pte; pte += (n); + + va = virtual_avail; + pte = pmap_pte(kernel_pmap, va); + + SYSMAP(caddr_t ,CMAP1 ,CADDR1 ,1 ) + SYSMAP(caddr_t ,CMAP2 ,CADDR2 ,1 ) + SYSMAP(caddr_t ,mmap ,vmmap ,1 ) + SYSMAP(struct msgbuf * ,msgbufmap ,msgbufp ,1 ) + virtual_avail = va; +#endif + /* + * reserve special hunk of memory for use by bus dma as a bounce + * buffer (contiguous virtual *and* physical memory). for now, + * assume vm does not use memory beneath hole, and we know that + * the bootstrap uses top 32k of base memory. -wfj + */ + { + extern vm_offset_t isaphysmem; + isaphysmem = va; + + virtual_avail = pmap_map(va, 0xa0000 - 32*1024, 0xa0000, VM_PROT_ALL); + } + + *(int *)PTD = 0; + load_cr3(rcr3()); + +} + +/* + * 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; +{ + vm_offset_t addr, addr2; + vm_size_t npg, s; + int rv; + extern int KPTphys; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_init(%x, %x)\n", phys_start, phys_end); +#endif + /* + * Now that kernel map has been allocated, we can mark as + * unavailable regions which we have mapped in locore. + */ + addr = atdevbase; + (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0, + &addr, (0x100000-0xa0000), FALSE); + + addr = (vm_offset_t) 0xfe000000+KPTphys/* *NBPG */; + vm_object_reference(kernel_object); + (void) vm_map_find(kernel_map, kernel_object, addr, + &addr, 2*NBPG, FALSE); + + /* + * Allocate memory for random pmap data structures. Includes the + * pv_head_table and pmap_attributes. + */ + npg = atop(phys_end - phys_start); + s = (vm_size_t) (sizeof(struct pv_entry) * npg + npg); + s = round_page(s); + addr = (vm_offset_t) kmem_alloc(kernel_map, s); + pv_table = (pv_entry_t) addr; + addr += sizeof(struct pv_entry) * npg; + pmap_attributes = (char *) addr; +#ifdef DEBUG + if (pmapdebug & PDB_INIT) + printf("pmap_init: %x bytes (%x pgs): tbl %x attr %x\n", + s, npg, pv_table, pmap_attributes); +#endif + + /* + * Now it is safe to enable pv_table recording. + */ + vm_first_phys = phys_start; + vm_last_phys = phys_end; + pmap_initialized = TRUE; +} + +/* + * Used to map a range of physical addresses into kernel + * virtual address space. + * + * For now, VM is already on, we only need to map the + * specified memory. + */ +vm_offset_t +pmap_map(virt, start, end, prot) + vm_offset_t virt; + vm_offset_t start; + vm_offset_t end; + int prot; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_map(%x, %x, %x, %x)\n", virt, start, end, prot); +#endif + while (start < end) { + pmap_enter(kernel_pmap, virt, start, prot, FALSE); + virt += PAGE_SIZE; + start += PAGE_SIZE; + } + return(virt); +} + +/* + * 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. + * + * [ just allocate a ptd and mark it uninitialize -- should we track + * with a table which process has which ptd? -wfj ] + */ + +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; +{ + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + pg("pmap_pinit(%x)\n", pmap); +#endif + + /* + * No need to allocate page table space yet but we do need a + * valid page directory table. + */ + pmap->pm_pdir = (pd_entry_t *) kmem_alloc(kernel_map, NBPG); + + /* wire in kernel global address entries */ + bcopy(PTD+KPTDI_FIRST, pmap->pm_pdir+KPTDI_FIRST, + (KPTDI_LAST-KPTDI_FIRST+1)*4); + + /* install self-referential address mapping entry */ + *(int *)(pmap->pm_pdir+PTDPTDI) = + (int)pmap_extract(kernel_pmap, pmap->pm_pdir) | PG_V | PG_URKW; + + pmap->pm_count = 1; + simple_lock_init(&pmap->pm_lock); +} + +/* + * 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) + 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 struct pmap *pmap; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + pg("pmap_release(%x)\n", pmap); +#endif +#ifdef notdef /* DIAGNOSTIC */ + /* count would be 0 from pmap_destroy... */ + simple_lock(&pmap->pm_lock); + if (pmap->pm_count != 1) + panic("pmap_release count"); +#endif + kmem_free(kernel_map, (vm_offset_t)pmap->pm_pdir, NBPG); +} + +/* + * Add a reference to the specified pmap. + */ +void +pmap_reference(pmap) + pmap_t pmap; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_reference(%x)", 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) + struct pmap *pmap; + register vm_offset_t sva; + register vm_offset_t eva; +{ + register pt_entry_t *ptp,*ptq; + vm_offset_t va; + vm_offset_t pa; + pt_entry_t *pte; + pv_entry_t pv, npv; + int ix; + int s, bits; +#ifdef DEBUG + pt_entry_t opte; + + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + pg("pmap_remove(%x, %x, %x)", pmap, sva, eva); +#endif + + if (pmap == NULL) + return; + + /* are we current address space or kernel? */ + if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum + || pmap == kernel_pmap) + ptp=PTmap; + + /* otherwise, we are alternate address space */ + else { + if (pmap->pm_pdir[PTDPTDI].pd_pfnum + != APTDpde.pd_pfnum) { + APTDpde = pmap->pm_pdir[PTDPTDI]; + tlbflush(); + } + ptp=APTmap; + } +#ifdef DEBUG + remove_stats.calls++; +#endif + + /* this is essential since we must check the PDE(sva) for precense */ + while (sva <= eva && !pmap_pde_v(pmap_pde(pmap, sva))) + sva = (sva & PD_MASK) + (1<<PD_SHIFT); + sva = i386_btop(sva); + eva = i386_btop(eva); + + for (; sva < eva; sva++) { + /* + * Weed out invalid mappings. + * Note: we assume that the page directory table is + * always allocated, and in kernel virtual. + */ + ptq=ptp+sva; + while((sva & 0x3ff) && !pmap_pte_pa(ptq)) + { + if(++sva >= eva) + return; + ptq++; + } + + + if(!(sva & 0x3ff)) /* Only check once in a while */ + { + if (!pmap_pde_v(pmap_pde(pmap, i386_ptob(sva)))) + { + /* We can race ahead here, straight to next pde.. */ + sva = (sva & 0xffc00) + (1<<10) -1 ; + continue; + } + } + if(!pmap_pte_pa(ptp+sva)) + continue; + + pte = ptp + sva; + pa = pmap_pte_pa(pte); + va = i386_ptob(sva); +#ifdef DEBUG + opte = *pte; + remove_stats.removes++; +#endif + /* + * Update statistics + */ + if (pmap_pte_w(pte)) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + + /* + * Invalidate the PTEs. + * XXX: should cluster them up and invalidate as many + * as possible at once. + */ +#ifdef DEBUG + if (pmapdebug & PDB_REMOVE) + printf("remove: inv %x ptes at %x(%x) ", + i386pagesperpage, pte, *(int *)pte); +#endif + bits = ix = 0; + do { + bits |= *(int *)pte & (PG_U|PG_M); + *(int *)pte++ = 0; + /*TBIS(va + ix * I386_PAGE_SIZE);*/ + } while (++ix != i386pagesperpage); + if (curproc && pmap == &curproc->p_vmspace->vm_pmap) + pmap_activate(pmap, (struct pcb *)curproc->p_addr); + /* are we current address space or kernel? */ + /*if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum + || pmap == kernel_pmap) + load_cr3(curpcb->pcb_ptd);*/ + tlbflush(); + +#ifdef needednotdone +reduce wiring count on page table pages as references drop +#endif + + /* + * Remove from the PV table (raise IPL since we + * may be called at interrupt time). + */ + if (pa < vm_first_phys || pa >= vm_last_phys) + continue; + 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) { + 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 { + for (npv = pv->pv_next; npv; npv = npv->pv_next) { +#ifdef DEBUG + remove_stats.pvsearch++; +#endif + if (pmap == npv->pv_pmap && va == npv->pv_va) + break; + pv = npv; + } +#ifdef DEBUG + if (npv == NULL) + panic("pmap_remove: PA not in pv_tab"); +#endif + pv->pv_next = npv->pv_next; + free((caddr_t)npv, M_VMPVENT); + pv = pa_to_pvh(pa); + } + +#ifdef notdef +[tally number of pagetable pages, if sharing of ptpages adjust here] +#endif + /* + * Update saved attributes for managed page + */ + pmap_attributes[pa_index(pa)] |= bits; + splx(s); + } +#ifdef notdef +[cache and tlb flushing, if needed] +#endif +} + +/* + * Routine: pmap_remove_all + * Function: + * Removes this physical page from + * all physical maps in which it resides. + * Reflects back modify bits to the pager. + */ +void +pmap_remove_all(pa) + vm_offset_t pa; +{ + register pv_entry_t pv; + int s; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + printf("pmap_remove_all(%x)", pa); + /*pmap_pvdump(pa);*/ +#endif + /* + * Not one of ours + */ + if (pa < vm_first_phys || pa >= vm_last_phys) + return; + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Do it the easy way for now + */ + while (pv->pv_pmap != NULL) { +#ifdef DEBUG + if (!pmap_pde_v(pmap_pde(pv->pv_pmap, pv->pv_va)) || + pmap_pte_pa(pmap_pte(pv->pv_pmap, pv->pv_va)) != pa) + panic("pmap_remove_all: bad mapping"); +#endif + pmap_remove(pv->pv_pmap, pv->pv_va, pv->pv_va + PAGE_SIZE); + } + splx(s); +} + +/* + * Routine: pmap_copy_on_write + * Function: + * Remove write privileges from all + * physical maps for this physical page. + */ +void +pmap_copy_on_write(pa) + vm_offset_t pa; +{ +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) + printf("pmap_copy_on_write(%x)", pa); +#endif + pmap_changebit(pa, PG_RO, TRUE); +} + +/* + * 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 pt_entry_t *pte; + register vm_offset_t va; + register int ix; + int i386prot; + boolean_t firstpage = TRUE; + register pt_entry_t *ptp; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) + printf("pmap_protect(%x, %x, %x, %x)", pmap, sva, eva, prot); +#endif + if (pmap == NULL) + return; + + if ((prot & VM_PROT_READ) == VM_PROT_NONE) { + pmap_remove(pmap, sva, eva); + return; + } + if (prot & VM_PROT_WRITE) + return; + + /* are we current address space or kernel? */ + if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum + || pmap == kernel_pmap) + ptp=PTmap; + + /* otherwise, we are alternate address space */ + else { + if (pmap->pm_pdir[PTDPTDI].pd_pfnum + != APTDpde.pd_pfnum) { + APTDpde = pmap->pm_pdir[PTDPTDI]; + tlbflush(); + } + ptp=APTmap; + } + for (va = sva; va < eva; va += PAGE_SIZE) { + /* + * Page table page is not allocated. + * Skip it, we don't want to force allocation + * of unnecessary PTE pages just to set the protection. + */ + if (!pmap_pde_v(pmap_pde(pmap, va))) { + /* XXX: avoid address wrap around */ + if (va >= i386_trunc_pdr((vm_offset_t)-1)) + break; + va = i386_round_pdr(va + PAGE_SIZE) - PAGE_SIZE; + continue; + } + + pte = ptp + i386_btop(va); + + /* + * Page not valid. Again, skip it. + * Should we do this? Or set protection anyway? + */ + if (!pmap_pte_v(pte)) + continue; + + ix = 0; + i386prot = pte_prot(pmap, prot); + if(va < UPT_MAX_ADDRESS) + i386prot |= 2 /*PG_u*/; + do { + /* clear VAC here if PG_RO? */ + pmap_pte_set_prot(pte++, i386prot); + /*TBIS(va + ix * I386_PAGE_SIZE);*/ + } while (++ix != i386pagesperpage); + } + if (curproc && pmap == &curproc->p_vmspace->vm_pmap) + pmap_activate(pmap, (struct pcb *)curproc->p_addr); +} + +/* + * 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 int npte, ix; + vm_offset_t opa; + boolean_t cacheable = TRUE; + boolean_t checkpv = TRUE; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_ENTER)) + printf("pmap_enter(%x, %x, %x, %x, %x)", + pmap, va, pa, prot, wired); +#endif + if (pmap == NULL) + return; + + if(va > VM_MAX_KERNEL_ADDRESS)panic("pmap_enter: toobig"); + /* also, should not muck with PTD va! */ + +#ifdef DEBUG + if (pmap == kernel_pmap) + enter_stats.kernel++; + else + enter_stats.user++; +#endif + + /* + * Page Directory table entry not valid, we need a new PT page + */ + if (!pmap_pde_v(pmap_pde(pmap, va))) { + pg("ptdi %x", pmap->pm_pdir[PTDPTDI]); + } + + pte = pmap_pte(pmap, va); + opa = pmap_pte_pa(pte); +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: pte %x, *pte %x ", pte, *(int *)pte); +#endif + + /* + * Mapping has not changed, must be protection or wiring change. + */ + if (opa == pa) { +#ifdef DEBUG + enter_stats.pwchange++; +#endif + /* + * Wiring change, just update stats. + * We don't worry about wiring PT pages as they remain + * resident as long as there are valid mappings in them. + * Hence, if a user page is wired, the PT page will be also. + */ + if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) { +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + pg("enter: wiring change -> %x ", wired); +#endif + if (wired) + pmap->pm_stats.wired_count++; + else + pmap->pm_stats.wired_count--; +#ifdef DEBUG + enter_stats.wchange++; +#endif + } + goto validate; + } + + /* + * Mapping has changed, invalidate old range and fall through to + * handle validating new mapping. + */ + if (opa) { +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: removing old mapping %x pa %x ", va, opa); +#endif + pmap_remove(pmap, va, va + PAGE_SIZE); +#ifdef DEBUG + enter_stats.mchange++; +#endif + } + + /* + * Enter on the PV list if part of our managed memory + * Note that we raise IPL while manipulating pv_table + * since pmap_enter can be called at interrupt time. + */ + if (pa >= vm_first_phys && pa < vm_last_phys) { + register pv_entry_t pv, npv; + int s; + +#ifdef DEBUG + enter_stats.managed++; +#endif + pv = pa_to_pvh(pa); + s = splimp(); +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: pv at %x: %x/%x/%x ", + pv, pv->pv_va, pv->pv_pmap, pv->pv_next); +#endif + /* + * No entries yet, use header as the first entry + */ + if (pv->pv_pmap == NULL) { +#ifdef DEBUG + enter_stats.firstpv++; +#endif + pv->pv_va = va; + pv->pv_pmap = pmap; + pv->pv_next = NULL; + pv->pv_flags = 0; + } + /* + * There is at least one other VA mapping this page. + * Place this entry after the header. + */ + else { + /*printf("second time: ");*/ +#ifdef DEBUG + for (npv = pv; npv; npv = npv->pv_next) + if (pmap == npv->pv_pmap && va == npv->pv_va) + panic("pmap_enter: already in pv_tab"); +#endif + 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; + pv->pv_next = npv; +#ifdef DEBUG + if (!npv->pv_next) + enter_stats.secondpv++; +#endif + } + splx(s); + } + /* + * Assumption: if it is not part of our managed memory + * then it must be device memory which may be volitile. + */ + if (pmap_initialized) { + checkpv = cacheable = FALSE; +#ifdef DEBUG + enter_stats.unmanaged++; +#endif + } + + /* + * Increment counters + */ + pmap->pm_stats.resident_count++; + if (wired) + pmap->pm_stats.wired_count++; + +validate: + /* + * Now validate mapping with desired protection/wiring. + * Assume uniform modified and referenced status for all + * I386 pages in a MACH page. + */ + npte = (pa & PG_FRAME) | pte_prot(pmap, prot) | PG_V; + npte |= (*(int *)pte & (PG_M|PG_U)); + if (wired) + npte |= PG_W; + if(va < UPT_MIN_ADDRESS) + npte |= PG_u; + else if(va < UPT_MAX_ADDRESS) + npte |= PG_u | PG_RW; +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: new pte value %x ", npte); +#endif + ix = 0; + do { + *(int *)pte++ = npte; + /*TBIS(va);*/ + npte += I386_PAGE_SIZE; + va += I386_PAGE_SIZE; + } while (++ix != i386pagesperpage); + pte--; +#ifdef DEBUGx +cache, tlb flushes +#endif +/*pads(pmap);*/ + /*load_cr3(((struct pcb *)curproc->p_addr)->pcb_ptd);*/ + tlbflush(); +} + +/* + * pmap_page_protect: + * + * Lower the permission for all mappings to a given page. + */ +void +pmap_page_protect(phys, prot) + vm_offset_t phys; + vm_prot_t prot; +{ + switch (prot) { + case VM_PROT_READ: + case VM_PROT_READ|VM_PROT_EXECUTE: + pmap_copy_on_write(phys); + break; + case VM_PROT_ALL: + break; + default: + pmap_remove_all(phys); + break; + } +} + +/* + * 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; + register int ix; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_change_wiring(%x, %x, %x)", pmap, va, wired); +#endif + if (pmap == NULL) + return; + + pte = pmap_pte(pmap, va); +#ifdef DEBUG + /* + * Page table page is not allocated. + * Should this ever happen? Ignore it for now, + * we don't want to force allocation of unnecessary PTE pages. + */ + if (!pmap_pde_v(pmap_pde(pmap, va))) { + if (pmapdebug & PDB_PARANOIA) + pg("pmap_change_wiring: invalid PDE for %x ", va); + return; + } + /* + * Page not valid. Should this ever happen? + * Just continue and change wiring anyway. + */ + if (!pmap_pte_v(pte)) { + if (pmapdebug & PDB_PARANOIA) + pg("pmap_change_wiring: invalid PTE for %x ", va); + } +#endif + if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) { + if (wired) + pmap->pm_stats.wired_count++; + else + pmap->pm_stats.wired_count--; + } + /* + * Wiring is not a hardware characteristic so there is no need + * to invalidate TLB. + */ + ix = 0; + do { + pmap_pte_set_w(pte++, wired); + } while (++ix != i386pagesperpage); +} + +/* + * Routine: pmap_pte + * Function: + * Extract the page table entry associated + * with the given map/virtual_address pair. + * [ what about induced faults -wfj] + */ + +struct pte *pmap_pte(pmap, va) + register pmap_t pmap; + vm_offset_t va; +{ + +#ifdef DEBUGx + if (pmapdebug & PDB_FOLLOW) + printf("pmap_pte(%x, %x) ->\n", pmap, va); +#endif + if (pmap && pmap_pde_v(pmap_pde(pmap, va))) { + + /* are we current address space or kernel? */ + if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum + || pmap == kernel_pmap) + return ((struct pte *) vtopte(va)); + + /* otherwise, we are alternate address space */ + else { + if (pmap->pm_pdir[PTDPTDI].pd_pfnum + != APTDpde.pd_pfnum) { + APTDpde = pmap->pm_pdir[PTDPTDI]; + tlbflush(); + } + return((struct pte *) avtopte(va)); + } + } + return(0); +} + +/* + * 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 DEBUGx + if (pmapdebug & PDB_FOLLOW) + pg("pmap_extract(%x, %x) -> ", pmap, va); +#endif + pa = 0; + if (pmap && pmap_pde_v(pmap_pde(pmap, va))) { + pa = *(int *) pmap_pte(pmap, va); + } + if (pa) + pa = (pa & PG_FRAME) | (va & ~PG_FRAME); +#ifdef DEBUGx + if (pmapdebug & PDB_FOLLOW) + printf("%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)", + 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()"); +#endif + tlbflush(); +} + +/* + * 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. + * [ needs to be written -wfj ] + */ +void +pmap_collect(pmap) + pmap_t pmap; +{ + register vm_offset_t pa; + register pv_entry_t pv; + register int *pte; + vm_offset_t kpa; + int s; + +#ifdef DEBUG + int *pde; + int opmapdebug; + printf("pmap_collect(%x) ", pmap); +#endif + if (pmap != kernel_pmap) + return; + +} + +/* [ macro again?, should I force kstack into user map here? -wfj ] */ +void +pmap_activate(pmap, pcbp) + register pmap_t pmap; + struct pcb *pcbp; +{ +int x; +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PDRTAB)) + pg("pmap_activate(%x, %x) ", pmap, pcbp); +#endif + PMAP_ACTIVATE(pmap, pcbp); +/*printf("pde "); +for(x=0x3f6; x < 0x3fA; x++) + printf("%x ", pmap->pm_pdir[x]);*/ +/*pads(pmap);*/ +/*pg(" pcb_cr3 %x", pcbp->pcb_cr3);*/ +} + +/* + * Routine: pmap_kernel + * Function: + * Returns the physical map handle for the kernel. + */ +pmap_t +pmap_kernel() +{ + return (kernel_pmap); +} + +/* + * pmap_zero_page zeros the specified (machine independent) + * page by mapping the page into virtual memory and using + * bzero to clear its contents, one machine dependent page + * at a time. + */ +pmap_zero_page(phys) + register vm_offset_t phys; +{ + register int ix; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_zero_page(%x)", phys); +#endif + phys >>= PG_SHIFT; + ix = 0; + do { + clearseg(phys++); + } while (++ix != i386pagesperpage); +} + +/* + * pmap_copy_page copies the specified (machine independent) + * page by mapping the page into virtual memory and using + * bcopy to copy the page, one machine dependent page at a + * time. + */ +pmap_copy_page(src, dst) + register vm_offset_t src, dst; +{ + register int ix; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy_page(%x, %x)", src, dst); +#endif + src >>= PG_SHIFT; + dst >>= PG_SHIFT; + ix = 0; + do { + physcopyseg(src++, dst++); + } while (++ix != i386pagesperpage); +} + + +/* + * 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. + */ +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)", + pmap, sva, eva, pageable); +#endif + /* + * If we are making a PT page pageable then all valid + * mappings must be gone from that page. Hence it should + * be all zeros and there is no need to clean it. + * Assumptions: + * - we are called with only one page at a time + * - PT pages have only one pv_table entry + */ + if (pmap == kernel_pmap && pageable && sva + PAGE_SIZE == eva) { + register pv_entry_t pv; + register vm_offset_t pa; + +#ifdef DEBUG + if ((pmapdebug & (PDB_FOLLOW|PDB_PTPAGE)) == PDB_PTPAGE) + printf("pmap_pageable(%x, %x, %x, %x)", + pmap, sva, eva, pageable); +#endif + /*if (!pmap_pde_v(pmap_pde(pmap, sva))) + return;*/ + if(pmap_pte(pmap, sva) == 0) + return; + pa = pmap_pte_pa(pmap_pte(pmap, sva)); + if (pa < vm_first_phys || pa >= vm_last_phys) + return; + pv = pa_to_pvh(pa); + /*if (!ispt(pv->pv_va)) + return;*/ +#ifdef DEBUG + if (pv->pv_va != sva || pv->pv_next) { + pg("pmap_pageable: bad PT page va %x next %x\n", + pv->pv_va, pv->pv_next); + return; + } +#endif + /* + * Mark it unmodified to avoid pageout + */ + pmap_clear_modify(pa); +#ifdef needsomethinglikethis + if (pmapdebug & PDB_PTPAGE) + pg("pmap_pageable: PT page %x(%x) unmodified\n", + sva, *(int *)pmap_pte(pmap, sva)); + if (pmapdebug & PDB_WIRING) + pmap_check_wiring("pageable", sva); +#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)", pa); +#endif + pmap_changebit(pa, PG_M, FALSE); +} + +/* + * 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)", pa); +#endif + pmap_changebit(pa, PG_U, FALSE); +} + +/* + * 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 DEBUG + if (pmapdebug & PDB_FOLLOW) { + boolean_t rv = pmap_testbit(pa, PG_U); + printf("pmap_is_referenced(%x) -> %c", pa, "FT"[rv]); + return(rv); + } +#endif + return(pmap_testbit(pa, PG_U)); +} + +/* + * 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 DEBUG + if (pmapdebug & PDB_FOLLOW) { + boolean_t rv = pmap_testbit(pa, PG_M); + printf("pmap_is_modified(%x) -> %c", pa, "FT"[rv]); + return(rv); + } +#endif + return(pmap_testbit(pa, PG_M)); +} + +vm_offset_t +pmap_phys_address(ppn) + int ppn; +{ + return(i386_ptob(ppn)); +} + +/* + * Miscellaneous support routines follow + */ + +i386_protection_init() +{ + register int *kp, prot; + + kp = protection_codes; + for (prot = 0; prot < 8; prot++) { + switch (prot) { + case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE: + *kp++ = 0; + break; + case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE: + case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE: + case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE: + *kp++ = PG_RO; + break; + case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE: + case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE: + case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE: + case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE: + *kp++ = PG_RW; + break; + } + } +} + +boolean_t +pmap_testbit(pa, bit) + register vm_offset_t pa; + int bit; +{ + register pv_entry_t pv; + register int *pte, ix; + int s; + + if (pa < vm_first_phys || pa >= vm_last_phys) + return(FALSE); + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Check saved info first + */ + if (pmap_attributes[pa_index(pa)] & bit) { + splx(s); + return(TRUE); + } + /* + * Not found, check current mappings returning + * immediately if found. + */ + if (pv->pv_pmap != NULL) { + for (; pv; pv = pv->pv_next) { + pte = (int *) pmap_pte(pv->pv_pmap, pv->pv_va); + ix = 0; + do { + if (*pte++ & bit) { + splx(s); + return(TRUE); + } + } while (++ix != i386pagesperpage); + } + } + splx(s); + return(FALSE); +} + +pmap_changebit(pa, bit, setem) + register vm_offset_t pa; + int bit; + boolean_t setem; +{ + register pv_entry_t pv; + register int *pte, npte, ix; + vm_offset_t va; + int s; + boolean_t firstpage = TRUE; + +#ifdef DEBUG + if (pmapdebug & PDB_BITS) + printf("pmap_changebit(%x, %x, %s)", + pa, bit, setem ? "set" : "clear"); +#endif + if (pa < vm_first_phys || pa >= vm_last_phys) + return; + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Clear saved attributes (modify, reference) + */ + if (!setem) + pmap_attributes[pa_index(pa)] &= ~bit; + /* + * Loop over all current mappings setting/clearing as appropos + * If setting RO do we need to clear the VAC? + */ + if (pv->pv_pmap != NULL) { +#ifdef DEBUG + int toflush = 0; +#endif + for (; pv; pv = pv->pv_next) { +#ifdef DEBUG + toflush |= (pv->pv_pmap == kernel_pmap) ? 2 : 1; +#endif + va = pv->pv_va; + + /* + * XXX don't write protect pager mappings + */ + if (bit == PG_RO) { + extern vm_offset_t pager_sva, pager_eva; + + if (va >= pager_sva && va < pager_eva) + continue; + } + + pte = (int *) pmap_pte(pv->pv_pmap, va); + ix = 0; + do { + if (setem) + npte = *pte | bit; + else + npte = *pte & ~bit; + if (*pte != npte) { + *pte = npte; + /*TBIS(va);*/ + } + va += I386_PAGE_SIZE; + pte++; + } while (++ix != i386pagesperpage); + + if (curproc && pv->pv_pmap == &curproc->p_vmspace->vm_pmap) + pmap_activate(pv->pv_pmap, (struct pcb *)curproc->p_addr); + } +#ifdef somethinglikethis + if (setem && bit == PG_RO && (pmapvacflush & PVF_PROTECT)) { + if ((pmapvacflush & PVF_TOTAL) || toflush == 3) + DCIA(); + else if (toflush == 2) + DCIS(); + else + DCIU(); + } +#endif + } + splx(s); +} + +#ifdef DEBUG +pmap_pvdump(pa) + vm_offset_t pa; +{ + register pv_entry_t pv; + + printf("pa %x", pa); + for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) { + printf(" -> pmap %x, va %x, flags %x", + pv->pv_pmap, pv->pv_va, pv->pv_flags); + pads(pv->pv_pmap); + } + printf(" "); +} + +#ifdef notyet +pmap_check_wiring(str, va) + char *str; + vm_offset_t va; +{ + vm_map_entry_t entry; + register int count, *pte; + + va = trunc_page(va); + if (!pmap_pde_v(pmap_pde(kernel_pmap, va)) || + !pmap_pte_v(pmap_pte(kernel_pmap, va))) + return; + + if (!vm_map_lookup_entry(pt_map, va, &entry)) { + pg("wired_check: entry for %x not found\n", va); + return; + } + count = 0; + for (pte = (int *)va; pte < (int *)(va+PAGE_SIZE); pte++) + if (*pte) + count++; + if (entry->wired_count != count) + pg("*%s*: %x: w%d/a%d\n", + str, va, entry->wired_count, count); +} +#endif + +/* print address space of pmap*/ +pads(pm) pmap_t pm; { + unsigned va, i, j; + struct pte *ptep; + + if(pm == kernel_pmap) return; + for (i = 0; i < 1024; i++) + if(pm->pm_pdir[i].pd_v) + for (j = 0; j < 1024 ; j++) { + va = (i<<22)+(j<<12); + if (pm == kernel_pmap && va < 0xfe000000) + continue; + if (pm != kernel_pmap && va > UPT_MAX_ADDRESS) + continue; + ptep = pmap_pte(pm, va); + if(pmap_pte_v(ptep)) + printf("%x:%x ", va, *(int *)ptep); + } ; + +} +#endif diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c new file mode 100644 index 000000000000..10b9ac274b40 --- /dev/null +++ b/sys/amd64/amd64/sys_machdep.c @@ -0,0 +1,105 @@ + +/*- + * 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. + * + * @(#)sys_machdep.c 5.5 (Berkeley) 1/19/91 + */ + +#include "param.h" +#include "systm.h" +#include "ioctl.h" +#include "file.h" +#include "time.h" +#include "proc.h" +#include "uio.h" +#include "kernel.h" +#include "mtio.h" +#include "buf.h" +#include "trace.h" + +#ifdef TRACE +int nvualarm; + +vtrace(p, uap, retval) + struct proc *p; + register struct args { + int request; + int value; + } *uap; + int *retval; +{ + int vdoualarm(); + + switch (uap->request) { + + case VTR_DISABLE: /* disable a trace point */ + case VTR_ENABLE: /* enable a trace point */ + if (uap->value < 0 || uap->value >= TR_NFLAGS) + return (EINVAL); + *retval = traceflags[uap->value]; + traceflags[uap->value] = uap->request; + break; + + case VTR_VALUE: /* return a trace point setting */ + if (uap->value < 0 || uap->value >= TR_NFLAGS) + return (EINVAL); + *retval = traceflags[uap->value]; + break; + + case VTR_UALARM: /* set a real-time ualarm, less than 1 min */ + if (uap->value <= 0 || uap->value > 60 * hz || nvualarm > 5) + return (EINVAL); + nvualarm++; + timeout(vdoualarm, (caddr_t)p->p_pid, uap->value); + break; + + case VTR_STAMP: + trace(TR_STAMP, 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 diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c new file mode 100644 index 000000000000..57195f32cb91 --- /dev/null +++ b/sys/amd64/amd64/trap.c @@ -0,0 +1,547 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the University of Utah, and 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. + * + * @(#)trap.c 7.4 (Berkeley) 5/13/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00137 + * -------------------- ----- ---------------------- + * + * 08 Apr 93 Bruce Evans Several VM system fixes + * Paul Kranenburg Add counter for vmstat + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/trap.c,v 1.2 92/01/21 14:22:13 william Exp $"; + +/* + * 386 Trap and System call handleing + */ + +#include "machine/cpu.h" +#include "machine/psl.h" +#include "machine/reg.h" + +#include "param.h" +#include "systm.h" +#include "proc.h" +#include "user.h" +#include "acct.h" +#include "kernel.h" +#ifdef KTRACE +#include "ktrace.h" +#endif + +#include "vm/vm_param.h" +#include "vm/pmap.h" +#include "vm/vm_map.h" +#include "sys/vmmeter.h" + +#include "machine/trap.h" + + +struct sysent sysent[]; +int nsysent; +int dostacklimits; +unsigned rcr2(); +extern short cpl; + + +/* + * trap(frame): + * Exception, fault, and trap interface to BSD kernel. This + * common code is called from assembly language IDT gate entry + * routines that prepare a suitable stack frame, and restore this + * frame after the exception has been processed. Note that the + * effect is as if the arguments were passed call by reference. + */ + +/*ARGSUSED*/ +trap(frame) + struct trapframe frame; +{ + register int i; + register struct proc *p = curproc; + struct timeval syst; + int ucode, type, code, eva; + + frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */ + type = frame.tf_trapno; +#include "ddb.h" +#if NDDB > 0 + if (curpcb && curpcb->pcb_onfault) { + if (frame.tf_trapno == T_BPTFLT + || frame.tf_trapno == T_TRCTRAP) + if (kdb_trap (type, 0, &frame)) + return; + } +#endif + +/*pg("trap type %d code = %x eip = %x cs = %x eva = %x esp %x", + frame.tf_trapno, frame.tf_err, frame.tf_eip, + frame.tf_cs, rcr2(), frame.tf_esp);*/ +if(curpcb == 0 || curproc == 0) goto we_re_toast; + if (curpcb->pcb_onfault && frame.tf_trapno != 0xc) { +copyfault: + frame.tf_eip = (int)curpcb->pcb_onfault; + return; + } + + syst = p->p_stime; + if (ISPL(frame.tf_cs) == SEL_UPL) { + type |= T_USER; + p->p_regs = (int *)&frame; + curpcb->pcb_flags |= FM_TRAP; /* used by sendsig */ + } + + ucode=0; + eva = rcr2(); + code = frame.tf_err; + switch (type) { + + default: + we_re_toast: +#ifdef KDB + if (kdb_trap(&psl)) + return; +#endif +#if NDDB > 0 + if (kdb_trap (type, 0, &frame)) + return; +#endif + + printf("trap type %d code = %x eip = %x cs = %x eflags = %x ", + frame.tf_trapno, frame.tf_err, frame.tf_eip, + frame.tf_cs, frame.tf_eflags); + eva = rcr2(); + printf("cr2 %x cpl %x\n", eva, cpl); + /* type &= ~T_USER; */ /* XXX what the hell is this */ + panic("trap"); + /*NOTREACHED*/ + + case T_SEGNPFLT|T_USER: + case T_STKFLT|T_USER: + case T_PROTFLT|T_USER: /* protection fault */ + ucode = code + BUS_SEGM_FAULT ; + i = SIGBUS; + break; + + case T_PRIVINFLT|T_USER: /* privileged instruction fault */ + case T_RESADFLT|T_USER: /* reserved addressing fault */ + case T_RESOPFLT|T_USER: /* reserved operand fault */ + case T_FPOPFLT|T_USER: /* coprocessor operand fault */ + ucode = type &~ T_USER; + i = SIGILL; + break; + + case T_ASTFLT|T_USER: /* Allow process switch */ + astoff(); + cnt.v_soft++; + if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) { + addupc(frame.tf_eip, &p->p_stats->p_prof, 1); + p->p_flag &= ~SOWEUPC; + } + goto out; + + case T_DNA|T_USER: +#ifdef NPX + /* if a transparent fault (due to context switch "late") */ + if (npxdna()) return; +#endif + i = math_emulate(&frame); + if (i == 0) return; + ucode = FPE_FPU_NP_TRAP; + break; + + case T_BOUND|T_USER: + ucode = FPE_SUBRNG_TRAP; + i = SIGFPE; + break; + + case T_OFLOW|T_USER: + ucode = FPE_INTOVF_TRAP; + i = SIGFPE; + break; + + case T_DIVIDE|T_USER: + ucode = FPE_INTDIV_TRAP; + i = SIGFPE; + break; + + case T_ARITHTRAP|T_USER: + ucode = code; + i = SIGFPE; + break; + + case T_PAGEFLT: /* allow page faults in kernel mode */ +#if 0 + /* XXX - check only applies to 386's and 486's with WP off */ + if (code & PGEX_P) goto we_re_toast; +#endif + + /* fall into */ + case T_PAGEFLT|T_USER: /* page fault */ + { + register vm_offset_t va; + register struct vmspace *vm = p->p_vmspace; + register vm_map_t map; + int rv; + vm_prot_t ftype; + extern vm_map_t kernel_map; + unsigned nss,v; + + va = trunc_page((vm_offset_t)eva); + /* + * Avoid even looking at pde_v(va) for high va's. va's + * above VM_MAX_KERNEL_ADDRESS don't correspond to normal + * PDE's (half of them correspond to APDEpde and half to + * an unmapped kernel PDE). va's betweeen 0xFEC00000 and + * VM_MAX_KERNEL_ADDRESS correspond to unmapped kernel PDE's + * (XXX - why are only 3 initialized when 6 are required to + * reach VM_MAX_KERNEL_ADDRESS?). Faulting in an unmapped + * kernel page table would give inconsistent PTD's. + * + * XXX - faulting in unmapped page tables wastes a page if + * va turns out to be invalid. + * + * XXX - should "kernel address space" cover the kernel page + * tables? Might have same problem with PDEpde as with + * APDEpde (or there may be no problem with APDEpde). + */ + if (va > 0xFEBFF000) { + rv = KERN_FAILURE; /* becomes SIGBUS */ + goto nogo; + } + /* + * It is only a kernel address space fault iff: + * 1. (type & T_USER) == 0 and + * 2. pcb_onfault not set or + * 3. pcb_onfault set but supervisor space fault + * The last can occur during an exec() copyin where the + * argument space is lazy-allocated. + */ + if (type == T_PAGEFLT && va >= KERNBASE) + map = kernel_map; + else + map = &vm->vm_map; + if (code & PGEX_W) + ftype = VM_PROT_READ | VM_PROT_WRITE; + else + ftype = VM_PROT_READ; + +#ifdef DEBUG + if (map == kernel_map && va == 0) { + printf("trap: bad kernel access at %x\n", va); + goto we_re_toast; + } +#endif + + /* + * XXX: rude hack to make stack limits "work" + */ + nss = 0; + if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map + && dostacklimits) { + nss = clrnd(btoc((unsigned)vm->vm_maxsaddr + + MAXSSIZ - (unsigned)va)); + if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) { +/*pg("trap rlimit %d, maxsaddr %x va %x ", nss, vm->vm_maxsaddr, va);*/ + rv = KERN_FAILURE; + goto nogo; + } + } + + /* check if page table is mapped, if not, fault it first */ +#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v) + if (!pde_v(va)) { + v = trunc_page(vtopte(va)); + rv = vm_fault(map, v, ftype, FALSE); + if (rv != KERN_SUCCESS) goto nogo; + /* check if page table fault, increment wiring */ + vm_map_pageable(map, v, round_page(v+1), FALSE); + } else v=0; + rv = vm_fault(map, va, ftype, FALSE); + if (rv == KERN_SUCCESS) { + /* + * XXX: continuation of rude stack hack + */ + if (nss > vm->vm_ssize) + vm->vm_ssize = nss; + va = trunc_page(vtopte(va)); + /* for page table, increment wiring + as long as not a page table fault as well */ + if (!v && type != T_PAGEFLT) + vm_map_pageable(map, va, round_page(va+1), FALSE); + if (type == T_PAGEFLT) + return; + goto out; + } +nogo: + if (type == T_PAGEFLT) { + if (curpcb->pcb_onfault) + goto copyfault; + printf("vm_fault(%x, %x, %x, 0) -> %x\n", + map, va, ftype, rv); + printf(" type %x, code %x\n", + type, code); + goto we_re_toast; + } + i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; + break; + } + +#if NDDB == 0 + case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */ + frame.tf_eflags &= ~PSL_T; + + /* Q: how do we turn it on again? */ + return; +#endif + + case T_BPTFLT|T_USER: /* bpt instruction fault */ + case T_TRCTRAP|T_USER: /* trace trap */ + frame.tf_eflags &= ~PSL_T; + i = SIGTRAP; + break; + +#include "isa.h" +#if NISA > 0 + case T_NMI: + case T_NMI|T_USER: +#if NDDB > 0 + /* NMI can be hooked up to a pushbutton for debugging */ + printf ("NMI ... going to debugger\n"); + if (kdb_trap (type, 0, &frame)) + return; +#endif + /* machine/parity/power fail/"kitchen sink" faults */ + if(isa_nmi(code) == 0) return; + else goto we_re_toast; +#endif + } + + trapsignal(p, i, ucode); + if ((type & T_USER) == 0) + return; +out: + while (i = CURSIG(p)) + psig(i); + p->p_pri = p->p_usrpri; + if (want_resched) { + /* + * 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 setrq ourselves but before we + * swtch()'ed, we might not be on the queue indicated by + * our priority. + */ + (void) splclock(); + setrq(p); + p->p_stats->p_ru.ru_nivcsw++; + swtch(); + (void) splnone(); + while (i = CURSIG(p)) + psig(i); + } + if (p->p_stats->p_prof.pr_scale) { + int ticks; + struct timeval *tv = &p->p_stime; + + ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + + (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); + if (ticks) { +#ifdef PROFTIMER + extern int profscale; + addupc(frame.tf_eip, &p->p_stats->p_prof, + ticks * profscale); +#else + addupc(frame.tf_eip, &p->p_stats->p_prof, ticks); +#endif + } + } + curpri = p->p_pri; + curpcb->pcb_flags &= ~FM_TRAP; /* used by sendsig */ +} + +/* + * Compensate for 386 brain damage (missing URKR) + */ +int trapwrite(unsigned addr) { + int rv; + vm_offset_t va; + + va = trunc_page((vm_offset_t)addr); + if (va > VM_MAXUSER_ADDRESS) return(1); + rv = vm_fault(&curproc->p_vmspace->vm_map, va, + VM_PROT_READ | VM_PROT_WRITE, FALSE); + if (rv == KERN_SUCCESS) return(0); + else return(1); +} + +/* + * syscall(frame): + * System call request from POSIX system call gate interface to kernel. + * Like trap(), argument is call by reference. + */ +/*ARGSUSED*/ +syscall(frame) + volatile struct syscframe frame; +{ + register int *locr0 = ((int *)&frame); + register caddr_t params; + register int i; + register struct sysent *callp; + register struct proc *p = curproc; + struct timeval syst; + int error, opc; + int args[8], rval[2]; + int code; + +#ifdef lint + r0 = 0; r0 = r0; r1 = 0; r1 = r1; +#endif + syst = p->p_stime; + if (ISPL(frame.sf_cs) != SEL_UPL) + panic("syscall"); + + code = frame.sf_eax; + curpcb->pcb_flags &= ~FM_TRAP; /* used by sendsig */ + p->p_regs = (int *)&frame; + params = (caddr_t)frame.sf_esp + sizeof (int) ; + + /* + * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always. + */ + opc = frame.sf_eip - 7; + callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; + if (callp == sysent) { + i = fuword(params); + params += sizeof (int); + callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; + } + + if ((i = callp->sy_narg * sizeof (int)) && + (error = copyin(params, (caddr_t)args, (u_int)i))) { + frame.sf_eax = error; + frame.sf_eflags |= PSL_C; /* carry bit */ +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, callp->sy_narg, &args); +#endif + goto done; + } +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, callp->sy_narg, &args); +#endif + rval[0] = 0; + rval[1] = frame.sf_edx; +/*pg("%d. s %d\n", p->p_pid, code);*/ + error = (*callp->sy_call)(p, args, rval); + if (error == ERESTART) + frame.sf_eip = opc; + else if (error != EJUSTRETURN) { + if (error) { +/*pg("error %d", error);*/ + frame.sf_eax = error; + frame.sf_eflags |= PSL_C; /* carry bit */ + } else { + frame.sf_eax = rval[0]; + frame.sf_edx = rval[1]; + frame.sf_eflags &= ~PSL_C; /* carry bit */ + } + } + /* else if (error == EJUSTRETURN) */ + /* nothing to do */ +done: + /* + * Reinitialize proc pointer `p' as it may be different + * if this is a child returning from fork syscall. + */ + p = curproc; + while (i = CURSIG(p)) + psig(i); + p->p_pri = p->p_usrpri; + if (want_resched) { + /* + * 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 setrq ourselves but before we + * swtch()'ed, we might not be on the queue indicated by + * our priority. + */ + (void) splclock(); + setrq(p); + p->p_stats->p_ru.ru_nivcsw++; + swtch(); + (void) splnone(); + while (i = CURSIG(p)) + psig(i); + } + if (p->p_stats->p_prof.pr_scale) { + int ticks; + struct timeval *tv = &p->p_stime; + + ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + + (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); + if (ticks) { +#ifdef PROFTIMER + extern int profscale; + addupc(frame.sf_eip, &p->p_stats->p_prof, + ticks * profscale); +#else + addupc(frame.sf_eip, &p->p_stats->p_prof, ticks); +#endif + } + } + curpri = p->p_pri; +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(p->p_tracep, code, error, rval[0]); +#endif +#ifdef DIAGNOSTICx +{ extern int _udatasel, _ucodesel; + if (frame.sf_ss != _udatasel) + printf("ss %x call %d\n", frame.sf_ss, code); + if ((frame.sf_cs&0xffff) != _ucodesel) + printf("cs %x call %d\n", frame.sf_cs, code); + if (frame.sf_eip > VM_MAXUSER_ADDRESS) { + printf("eip %x call %d\n", frame.sf_eip, code); + frame.sf_eip = 0; + } +} +#endif +} diff --git a/sys/amd64/amd64/tsc.c b/sys/amd64/amd64/tsc.c new file mode 100644 index 000000000000..0fb77012d090 --- /dev/null +++ b/sys/amd64/amd64/tsc.c @@ -0,0 +1,271 @@ +/*- + * 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. + * + * @(#)clock.c 7.2 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 5 00158 + * -------------------- ----- ---------------------- + * + * 14 Aug 92 Arne Henrik Juul Added code in the kernel to + * allow for DST in the BIOS. + * 17 Jan 93 Bruce Evans Fixed leap year and second + * calculations + * 01 Feb 93 Julian Elischer Added code to for the cpu + * speed independent spinwait() + * function, (used by scsi and others) + * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1 + * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock + * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait + * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I + * still kept the other fixes... Had to + * add back in findcpuspeed that Bruce + * had removed. + */ + +/* + * Primitive clock interrupt routines. + */ +#include "param.h" +#include "systm.h" +#include "time.h" +#include "kernel.h" +#include "machine/segments.h" +#include "i386/isa/icu.h" +#include "i386/isa/isa.h" +#include "i386/isa/rtc.h" +#include "i386/isa/timerreg.h" + +#define DAYST 119 +#define DAYEN 303 + +/* X-tals being what they are, it's nice to be able to fudge this one... */ +/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */ +#ifndef TIMER_FREQ +#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */ +#endif + +startrtclock() { + int s; + + findcpuspeed(); /* use the clock (while it's free) + to find the cpu speed */ + /* initialize 8253 clock */ + outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); + + /* Correct rounding will buy us a better precision in timekeeping */ + outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz); + outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256); + + /* initialize brain-dead battery powered clock */ + outb (IO_RTC, RTC_STATUSA); + outb (IO_RTC+1, 0x26); + outb (IO_RTC, RTC_STATUSB); + outb (IO_RTC+1, 2); + + outb (IO_RTC, RTC_DIAG); + if (s = inb (IO_RTC+1)) + printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); + outb (IO_RTC, RTC_DIAG); + outb (IO_RTC+1, 0); +} + +unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ + +#define FIRST_GUESS 0x2000 +findcpuspeed() +{ + unsigned char low; + unsigned int remainder; + + /* Put counter in count down mode */ + outb(IO_TIMER1+3, 0x34); + outb(IO_TIMER1, 0xff); + outb(IO_TIMER1, 0xff); + delaycount = FIRST_GUESS; + spinwait(1); + /* Read the value left in the counter */ + low = inb(IO_TIMER1); /* least siginifcant */ + remainder = inb(IO_TIMER1); /* most significant */ + remainder = (remainder<<8) + low ; + /* Formula for delaycount is : + * (loopcount * timer clock speed)/ (counter ticks * 1000) + */ + delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder); +} + + +/* convert 2 digit BCD number */ +bcd(i) +int i; +{ + return ((i/16)*10 + (i%16)); +} + +/* convert years to seconds (from 1970) */ +unsigned long +ytos(y) +int y; +{ + int i; + unsigned long ret; + + ret = 0; + for(i = 1970; i < y; i++) { + if (i % 4) ret += 365*24*60*60; + else ret += 366*24*60*60; + } + return ret; +} + +/* convert months to seconds */ +unsigned long +mtos(m,leap) +int m,leap; +{ + int i; + unsigned long ret; + + ret = 0; + for(i=1;i<m;i++) { + switch(i){ + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + ret += 31*24*60*60; break; + case 4: case 6: case 9: case 11: + ret += 30*24*60*60; break; + case 2: + if (leap) ret += 29*24*60*60; + else ret += 28*24*60*60; + } + } + return ret; +} + + +/* + * Initialize the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +inittodr(base) + time_t base; +{ + unsigned long sec; + int leap,day_week,t,yd; + int sa,s; + + /* do we have a realtime clock present? (otherwise we loop below) */ + sa = rtcin(RTC_STATUSA); + if (sa == 0xff || sa == 0) return; + + /* ready for a read? */ + while ((sa&RTCSA_TUP) == RTCSA_TUP) + sa = rtcin(RTC_STATUSA); + + sec = bcd(rtcin(RTC_YEAR)) + 1900; + if (sec < 1970) + sec += 100; + leap = !(sec % 4); sec = ytos(sec); /* year */ + yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */ + t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */ + day_week = rtcin(RTC_WDAY); /* day */ + sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */ + sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */ + sec += bcd(rtcin(RTC_SEC)); /* seconds */ + + /* XXX off by one? Need to calculate DST on SUNDAY */ + /* Perhaps we should have the RTC hold GMT time to save */ + /* us the bother of converting. */ + yd = yd / (24*60*60); + if ((yd >= DAYST) && ( yd <= DAYEN)) { + sec -= 60*60; + } + sec += tz.tz_minuteswest * 60; + + time.tv_sec = sec; +} + +#ifdef garbage +/* + * Initialze the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +test_inittodr(base) + time_t base; +{ + + outb(IO_RTC,9); /* year */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,8); /* month */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,7); /* day */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,4); /* hour */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,2); /* minutes */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,0); /* seconds */ + printf("%d\n",bcd(inb(IO_RTC+1))); + + time.tv_sec = base; +} +#endif + +/* + * Restart the clock. + */ +resettodr() +{ +} + +/* + * Wire clock interrupt in. + */ +#define V(s) __CONCAT(V, s) +extern V(clk)(); +enablertclock() { + setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); + INTREN(IRQ0); +} + +/* + * Delay for some number of milliseconds. + */ +void +spinwait(millisecs) + int millisecs; +{ + DELAY(1000 * millisecs); +} diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c new file mode 100644 index 000000000000..27ef912e8519 --- /dev/null +++ b/sys/amd64/amd64/vm_machdep.c @@ -0,0 +1,410 @@ +/*- + * Copyright (c) 1982, 1986 The Regents of the University of California. + * Copyright (c) 1989, 1990 William Jolitz + * 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 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. + * + * @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Bruce Evans New npx-0.5 code + * + */ + +/* + * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/vm_machdep.c,v 1.2 92/01/21 14:22:17 william Exp $"; + +#include "param.h" +#include "systm.h" +#include "proc.h" +#include "malloc.h" +#include "buf.h" +#include "user.h" + +#include "../include/cpu.h" + +#include "vm/vm.h" +#include "vm/vm_kern.h" + +/* + * 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; + int foo, offset, addr, i; + extern char kstack[]; + extern int mvesp(); + + /* + * 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; + * this is tricky, as the final pcb is constructed by savectx, + * but its frame isn't yet on the stack when the stack is copied. + * swtch compensates for this when the child eventually runs. + * This should be done differently, with a single call + * that copies and updates the pcb+stack, + * replacing the bcopy and savectx. + */ + p2->p_addr->u_pcb = p1->p_addr->u_pcb; + offset = mvesp() - (int)kstack; + bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset, + (unsigned) ctob(UPAGES) - offset); + p2->p_regs = p1->p_regs; + + /* + * Wire top of address space of child to it's kstack. + * First, fault in a page of pte's to map it. + */ + addr = trunc_page((u_int)vtopte(kstack)); + vm_map_pageable(&p2->p_vmspace->vm_map, addr, addr+NBPG, FALSE); + for (i=0; i < UPAGES; i++) + pmap_enter(&p2->p_vmspace->vm_pmap, kstack+i*NBPG, + pmap_extract(kernel_pmap, ((int)p2->p_addr)+i*NBPG), VM_PROT_READ, 1); + + pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb); + + /* + * + * Arrange for a non-local goto when the new process + * is started, to resume here, returning nonzero from setjmp. + */ + if (savectx(up, 1)) { + /* + * Return 1 in child. + */ + return (1); + } + return (0); +} + +#ifdef notyet +/* + * cpu_exit is called as the last action during exit. + * + * We change to an inactive address space and a "safe" stack, + * passing thru an argument to the new stack. Now, safely isolated + * from the resources we're shedding, we release the address space + * and any remaining machine-dependent resources, including the + * memory for the user structure and kernel stack. + * + * Next, we assign a dummy context to be written over by swtch, + * calling it to send this process off to oblivion. + * [The nullpcb allows us to minimize cost in swtch() by not having + * a special case]. + */ +struct proc *swtch_to_inactive(); +cpu_exit(p) + register struct proc *p; +{ + static struct pcb nullpcb; /* pcb to overwrite on last swtch */ + +#ifdef NPX + npxexit(p); +#endif + + /* move to inactive space and stack, passing arg accross */ + p = swtch_to_inactive(p); + + /* drop per-process resources */ + vmspace_free(p->p_vmspace); + kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES)); + + p->p_addr = (struct user *) &nullpcb; + splclock(); + swtch(); + /* NOTREACHED */ +} +#else +cpu_exit(p) + register struct proc *p; +{ + +#ifdef NPX + npxexit(p); +#endif + splclock(); + swtch(); +} + +cpu_wait(p) struct proc *p; { + + /* drop per-process resources */ + vmspace_free(p->p_vmspace); + kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES)); +} +#endif + +/* + * Set a red zone in the kernel stack after the u. area. + */ +setredzone(pte, vaddr) + u_short *pte; + caddr_t vaddr; +{ +/* eventually do this by setting up an expand-down stack segment + for ss0: selector, allowing stack access down to top of u. + this means though that protection violations need to be handled + thru a double fault exception that must do an integral task + switch to a known good context, within which a dump can be + taken. a sensible scheme might be to save the initial context + used by sched (that has physical memory mapped 1:1 at bottom) + and take the dump while still in mapped mode */ +} + +/* + * 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. + */ +pagemove(from, to, size) + register caddr_t from, to; + int size; +{ + register struct pte *fpte, *tpte; + + if (size % CLBYTES) + panic("pagemove"); + fpte = kvtopte(from); + tpte = kvtopte(to); + while (size > 0) { + *tpte++ = *fpte; + *(int *)fpte++ = 0; + from += NBPG; + to += NBPG; + size -= NBPG; + } + tlbflush(); +} + +/* + * Convert kernel VA to physical address + */ +kvtop(addr) + register caddr_t addr; +{ + vm_offset_t va; + + va = pmap_extract(kernel_pmap, (vm_offset_t)addr); + if (va == 0) + panic("kvtop: zero page frame"); + return((int)va); +} + +#ifdef notdef +/* + * The probe[rw] routines should probably be redone in assembler + * for efficiency. + */ +prober(addr) + register u_int addr; +{ + register int page; + register struct proc *p; + + if (addr >= USRSTACK) + return(0); + p = u.u_procp; + page = btop(addr); + if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize)) + return(1); + return(0); +} + +probew(addr) + register u_int addr; +{ + register int page; + register struct proc *p; + + if (addr >= USRSTACK) + return(0); + p = u.u_procp; + page = btop(addr); + if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize)) + return((*(int *)vtopte(p, page) & PG_PROT) == PG_UW); + return(0); +} + +/* + * NB: assumes a physically contiguous kernel page table + * (makes life a LOT simpler). + */ +kernacc(addr, count, rw) + register u_int addr; + int count, rw; +{ + register struct pde *pde; + register struct pte *pte; + register int ix, cnt; + extern long Syssize; + + if (count <= 0) + return(0); + pde = (struct pde *)((u_int)u.u_procp->p_p0br + u.u_procp->p_szpt * NBPG); + ix = (addr & PD_MASK) >> PD_SHIFT; + cnt = ((addr + count + (1 << PD_SHIFT) - 1) & PD_MASK) >> PD_SHIFT; + cnt -= ix; + for (pde += ix; cnt; cnt--, pde++) + if (pde->pd_v == 0) + return(0); + ix = btop(addr-0xfe000000); + cnt = btop(addr-0xfe000000+count+NBPG-1); + if (cnt > (int)&Syssize) + return(0); + cnt -= ix; + for (pte = &Sysmap[ix]; cnt; cnt--, pte++) + if (pte->pg_v == 0 /*|| (rw == B_WRITE && pte->pg_prot == 1)*/) + return(0); + return(1); +} + +useracc(addr, count, rw) + register u_int addr; + int count, rw; +{ + register int (*func)(); + register u_int addr2; + extern int prober(), probew(); + + if (count <= 0) + return(0); + addr2 = addr; + addr += count; + func = (rw == B_READ) ? prober : probew; + do { + if ((*func)(addr2) == 0) + return(0); + addr2 = (addr2 + NBPG) & ~PGOFSET; + } while (addr2 < addr); + return(1); +} +#endif + +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 useriomap + * (a name with only slightly more meaning than "kernelmap") + */ +vmapbuf(bp) + register struct buf *bp; +{ + register int npf; + register caddr_t addr; + register long flags = bp->b_flags; + struct proc *p; + int off; + vm_offset_t kva; + register vm_offset_t pa; + + if ((flags & B_PHYS) == 0) + panic("vmapbuf"); + addr = bp->b_saveaddr = bp->b_un.b_addr; + off = (int)addr & PGOFSET; + p = bp->b_proc; + npf = btoc(round_page(bp->b_bcount + off)); + kva = kmem_alloc_wait(phys_map, ctob(npf)); + bp->b_un.b_addr = (caddr_t) (kva + off); + while (npf--) { + pa = pmap_extract(&p->p_vmspace->vm_pmap, (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. + */ +vunmapbuf(bp) + register struct buf *bp; +{ + register int npf; + register caddr_t addr = bp->b_un.b_addr; + vm_offset_t kva; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vunmapbuf"); + npf = btoc(round_page(bp->b_bcount + ((int)addr & PGOFSET))); + kva = (vm_offset_t)((int)addr & ~PGOFSET); + kmem_free_wakeup(phys_map, kva, ctob(npf)); + bp->b_un.b_addr = bp->b_saveaddr; + bp->b_saveaddr = NULL; +} + +/* + * Force reset the processor by invalidating the entire address space! + */ +cpu_reset() { + + /* force a shutdown by unmapping entire address space ! */ + bzero((caddr_t) PTD, NBPG); + + /* "good night, sweet prince .... <THUNK!>" */ + tlbflush(); + /* NOTREACHED */ +} diff --git a/sys/amd64/include/cpu.h b/sys/amd64/include/cpu.h new file mode 100644 index 000000000000..583d76c98506 --- /dev/null +++ b/sys/amd64/include/cpu.h @@ -0,0 +1,108 @@ +/*- + * 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. + * + * @(#)cpu.h 5.4 (Berkeley) 5/9/91 + */ + +/* + * Definitions unique to i386 cpu support. + */ +#include "machine/frame.h" +#include "machine/segments.h" + +/* + * definitions of cpu-dependent requirements + * referenced in generic code + */ +#undef COPY_SIGCODE /* don't copy sigcode above user stack in exec */ + +/* + * function vs. inline configuration; + * these are defined to get generic functions + * rather than inline or machine-dependent implementations + */ +#define NEED_MINMAX /* need {,i,l,ul}{min,max} functions */ +#define NEED_FFS /* need ffs function */ +#define NEED_BCMP /* need bcmp function */ +#define NEED_STRLEN /* need strlen function */ + +#define cpu_exec(p) /* nothing */ + +/* + * Arguments to hardclock, softclock and gatherstats + * encapsulate the previous machine state in an opaque + * clockframe; for now, use generic intrframe. + */ +typedef struct intrframe clockframe; + +#define CLKF_USERMODE(framep) (ISPL((framep)->if_cs) == SEL_UPL) +#define CLKF_BASEPRI(framep) ((framep)->if_ppl == 0) +#define CLKF_PC(framep) ((framep)->if_eip) + +#define resettodr() /* no todr to set */ + +/* + * 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++; aston(); } + +/* + * Give a profiling tick to the current process from the softclock + * interrupt. On tahoe, request an ast to send us through trap(), + * marking the proc as needing a profiling tick. + */ +#define profile_tick(p, framep) { (p)->p_flag |= SOWEUPC; aston(); } + +/* + * Notify the current process (p) that it has a signal pending, + * process as soon as possible. + */ +#define signotify(p) aston() + +#define aston() (astpending++) + +int astpending; /* need to trap before returning to user mode */ +int want_resched; /* resched() was called */ + +/* + * Kinds of processor + */ + +#define CPU_386SX 0 +#define CPU_386 1 +#define CPU_486SX 2 +#define CPU_486 3 +#define CPU_586 4 diff --git a/sys/amd64/include/cpufunc.h b/sys/amd64/include/cpufunc.h new file mode 100644 index 000000000000..e3b4a8c9c052 --- /dev/null +++ b/sys/amd64/include/cpufunc.h @@ -0,0 +1,82 @@ +/* + * Functions to provide access to special i386 instructions. + * XXX - bezillions more are defined in locore.s but are not declared anywhere. + */ + +#include <sys/cdefs.h> +#include <sys/types.h> + +#ifdef __GNUC__ + +static __inline int bdb(void) +{ + extern int bdb_exists; + + if (!bdb_exists) + return (0); + __asm("int $3"); + return (1); +} + +static __inline void +disable_intr(void) +{ + __asm __volatile("cli"); +} + +static __inline void +enable_intr(void) +{ + __asm __volatile("sti"); +} + +/* + * This roundabout method of returning a u_char helps stop gcc-1.40 from + * generating unnecessary movzbl's. + */ +#define inb(port) ((u_char) u_int_inb(port)) + +static __inline u_int +u_int_inb(u_int port) +{ + u_char data; + /* + * We use %%dx and not %1 here because i/o is done at %dx and not at + * %edx, while gcc-2.2.2 generates inferior code (movw instead of movl) + * if we tell it to load (u_short) port. + */ + __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); + return data; +} + +static __inline void +outb(u_int port, u_char data) +{ + register u_char al asm("ax"); + + al = data; /* help gcc-1.40's register allocator */ + __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); +} + +#else /* not __GNUC__ */ + +int bdb __P((void)); +void disable_intr __P((void)); +void enable_intr __P((void)); +u_char inb __P((u_int port)); +void outb __P((u_int port, u_int data)); /* XXX - incompat */ + +#endif /* __GNUC__ */ + +#define really_u_int int /* XXX */ +#define really_void int /* XXX */ + +void load_cr0 __P((u_int cr0)); +really_u_int rcr0 __P((void)); + +#ifdef notyet +really_void setidt __P((int idx, /*XXX*/caddr_t func, int typ, int dpl)); +#endif + +#undef really_u_int +#undef really_void diff --git a/sys/amd64/include/db_machdep.h b/sys/amd64/include/db_machdep.h new file mode 100644 index 000000000000..8e37eec43fbc --- /dev/null +++ b/sys/amd64/include/db_machdep.h @@ -0,0 +1,154 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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. + */ +/* + * HISTORY + * $Log: db_machdep.h,v $ + * Revision 2.8 92/02/19 15:07:56 elf + * Added db_thread_fp_used. + * [92/02/19 rpd] + * + * Revision 2.7 91/10/09 16:06:28 af + * Revision 2.6.3.1 91/10/05 13:10:32 jeffreyh + * Added access and task name macros. + * [91/08/29 tak] + * + * Revision 2.6.3.1 91/10/05 13:10:32 jeffreyh + * Added access and task name macros. + * [91/08/29 tak] + * + * Revision 2.6 91/05/14 16:05:58 mrt + * Correcting copyright + * + * Revision 2.5 91/02/05 17:11:17 mrt + * Changed to new Mach copyright + * [91/02/01 17:31:24 mrt] + * + * Revision 2.4 91/01/08 15:10:16 rpd + * Added dummy inst_load/inst_store macros. + * [90/12/11 rpd] + * + * Revision 2.3 90/10/25 14:44:49 rwd + * Added watchpoint support. + * [90/10/18 rpd] + * + * Revision 2.2 90/08/27 21:56:15 dbg + * Created. + * [90/07/25 dbg] + * + */ + +#ifndef _I386_DB_MACHDEP_H_ +#define _I386_DB_MACHDEP_H_ + +/* + * Machine-dependent defines for new kernel debugger. + */ + + +/* #include <mach/i386/vm_types.h> */ +/* #include <mach/i386/vm_param.h> */ +#include <vm/vm_prot.h> +#include <vm/vm_param.h> +#include <vm/vm_inherit.h> +#include <vm/lock.h> +/* #include <i386/thread.h> */ /* for thread_status */ +#include <machine/frame.h> /* for struct trapframe */ +/* #include <i386/eflags.h> */ +#include <machine/eflags.h> /* from Mach... */ +/* #include <i386/trap.h> */ +#include <machine/trap.h> + +#define i386_saved_state trapframe +/* end of mangling */ + +typedef vm_offset_t db_addr_t; /* address - unsigned */ +typedef int db_expr_t; /* expression - signed */ + +typedef struct i386_saved_state db_regs_t; +db_regs_t ddb_regs; /* register state */ +#define DDB_REGS (&ddb_regs) + +#define PC_REGS(regs) ((db_addr_t)(regs)->tf_eip) + +#define BKPT_INST 0xcc /* breakpoint instruction */ +#define BKPT_SIZE (1) /* size of breakpoint inst */ +#define BKPT_SET(inst) (BKPT_INST) + +#define FIXUP_PC_AFTER_BREAK ddb_regs.tf_eip -= 1; + +#define db_clear_single_step(regs) ((regs)->tf_eflags &= ~EFL_TF) +#define db_set_single_step(regs) ((regs)->tf_eflags |= EFL_TF) + +/* #define IS_BREAKPOINT_TRAP(type, code) ((type) == T_INT3) */ +/* #define IS_WATCHPOINT_TRAP(type, code) ((type) == T_WATCHPOINT) */ +/* using the 386bsd values, rather than the Mach ones: */ +#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT) +#define IS_WATCHPOINT_TRAP(type, code) ((type) == T_KDBTRAP) + +#define I_CALL 0xe8 +#define I_CALLI 0xff +#define I_RET 0xc3 +#define I_IRET 0xcf + +#define inst_trap_return(ins) (((ins)&0xff) == I_IRET) +#define inst_return(ins) (((ins)&0xff) == I_RET) +#define inst_call(ins) (((ins)&0xff) == I_CALL || \ + (((ins)&0xff) == I_CALLI && \ + ((ins)&0x3800) == 0x1000)) +#define inst_load(ins) 0 +#define inst_store(ins) 0 + +/* access capability and access macros */ + +#define DB_ACCESS_LEVEL 2 /* access any space */ +#define DB_CHECK_ACCESS(addr,size,task) \ + db_check_access(addr,size,task) +#define DB_PHYS_EQ(task1,addr1,task2,addr2) \ + db_phys_eq(task1,addr1,task2,addr2) +#define DB_VALID_KERN_ADDR(addr) \ + ((addr) >= VM_MIN_KERNEL_ADDRESS && \ + (addr) < VM_MAX_KERNEL_ADDRESS) +#define DB_VALID_ADDRESS(addr,user) \ + ((!(user) && DB_VALID_KERN_ADDR(addr)) || \ + ((user) && (addr) < VM_MIN_KERNEL_ADDRESS)) + +boolean_t db_check_access(/* vm_offset_t, int, task_t */); +boolean_t db_phys_eq(/* task_t, vm_offset_t, task_t, vm_offset_t */); + +/* macros for printing OS server dependent task name */ + +#define DB_TASK_NAME(task) db_task_name(task) +#define DB_TASK_NAME_TITLE "COMMAND " +#define DB_TASK_NAME_LEN 23 +#define DB_NULL_TASK_NAME "? " + +void db_task_name(/* task_t */); + +/* macro for checking if a thread has used floating-point */ + +#define db_thread_fp_used(thread) ((thread)->pcb->ims.ifps != 0) + +#endif /* _I386_DB_MACHDEP_H_ */ diff --git a/sys/amd64/include/float.h b/sys/amd64/include/float.h new file mode 100644 index 000000000000..edfe0d929199 --- /dev/null +++ b/sys/amd64/include/float.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1989 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 7.1 (Berkeley) 5/8/90 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00086 + * -------------------- ----- ---------------------- + * + * 27 Feb 93 Handel/da Silva/Poirot Adjust value for MAX_DOUBLE + */ + +#define FLT_RADIX 2 /* b */ +#define FLT_ROUNDS 1 /* FP addition rounds to nearest */ + +#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.797693134862315E+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 diff --git a/sys/amd64/include/fpu.h b/sys/amd64/include/fpu.h new file mode 100644 index 000000000000..134e0c12aee8 --- /dev/null +++ b/sys/amd64/include/fpu.h @@ -0,0 +1,146 @@ +/*- + * 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. + * + * @(#)npx.h 5.3 (Berkeley) 1/18/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Bruce Evans New npx-0.5 code + * + */ + +/* + * 287/387 NPX Coprocessor Data Structures and Constants + * W. Jolitz 1/90 + */ + +#ifndef ___NPX87___ +#define ___NPX87___ + +/* Environment information of floating point unit */ +struct env87 { + long en_cw; /* control word (16bits) */ + long en_sw; /* status word (16bits) */ + long en_tw; /* tag word (16bits) */ + long en_fip; /* floating point instruction pointer */ + u_short en_fcs; /* floating code segment selector */ + u_short en_opcode; /* opcode last executed (11 bits ) */ + long en_foo; /* floating operand offset */ + long en_fos; /* floating operand segment selector */ +}; + +/* Contents of each floating point accumulator */ +struct fpacc87 { +#ifdef dontdef /* too unportable */ + u_long fp_mantlo; /* mantissa low (31:0) */ + u_long fp_manthi; /* mantissa high (63:32) */ + int fp_exp:15; /* exponent */ + int fp_sgn:1; /* mantissa sign */ +#else + u_char fp_bytes[10]; +#endif +}; + +/* Floating point context */ +struct save87 { + struct env87 sv_env; /* floating point control/status */ + struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */ +#ifndef dontdef + u_long sv_ex_sw; /* status word for last exception (was pad) */ + u_long sv_ex_tw; /* tag word for last exception (was pad) */ + u_char sv_pad[8 * 2 - 2 * 4]; /* bogus historical padding */ +#endif +}; + +/* Cyrix EMC memory - mapped coprocessor context switch information */ +struct emcsts { + long em_msw; /* memory mapped status register when swtched */ + long em_tar; /* memory mapped temp A register when swtched */ + long em_dl; /* memory mapped D low register when swtched */ +}; + +/* Intel prefers long real (53 bit) precision */ +#define __iBCS_NPXCW__ 0x262 +/* wfj prefers temporary real (64 bit) precision */ +#define __386BSD_NPXCW__ 0x362 +/* + * bde prefers 53 bit precision and all exceptions masked. + * + * The standard control word from finit is 0x37F, giving: + * + * round to nearest + * 64-bit precision + * all exceptions masked. + * + * Now I want: + * + * affine mode for 287's (if they work at all) (1 in bitfield 1<<12) + * 53-bit precision (2 in bitfield 3<<8) + * overflow exception unmasked (0 in bitfield 1<<3) + * zero divide exception unmasked (0 in bitfield 1<<2) + * invalid-operand exception unmasked (0 in bitfield 1<<0). + * + * 64-bit precision often gives bad results with high level languages + * because it makes the results of calculations depend on whether + * intermediate values are stored in memory or in FPU registers. + * + * The "Intel" and wfj control words have: + * + * underflow exception unmasked (0 in bitfield 1<<4) + * + * but that causes an unexpected exception in the test program 'paranoia' + * and makes denormals useless (DBL_MIN / 2 underflows). It doesn't make + * a lot of sense to trap underflow without trapping denormals. + * + * Later I will want the IEEE default of all exceptions masked. See the + * 0.0 math manpage for why this is better. The 0.1 math manpage is empty. + */ +#define __BDE_NPXCW__ 0x1272 +#define __BETTER_BDE_NPXCW__ 0x127f + +#ifdef __BROKEN_NPXCW__ +#ifdef __386BSD__ +#define __INITIAL_NPXCW__ __386BSD_NPXCW__ +#else +#define __INITIAL_NPXCW__ __iBCS_NPXCW__ +#endif +#else +#define __INITIAL_NPXCW__ __BDE_NPXCW__ +#endif + +#endif ___NPX87___ diff --git a/sys/amd64/include/frame.h b/sys/amd64/include/frame.h new file mode 100644 index 000000000000..4dbabd1935ce --- /dev/null +++ b/sys/amd64/include/frame.h @@ -0,0 +1,116 @@ +/*- + * 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. + * + * @(#)frame.h 5.2 (Berkeley) 1/18/91 + */ + +/* + * System stack frames. + */ + +/* + * Exception/Trap Stack Frame + */ + +struct trapframe { + int tf_es; + int tf_ds; + int tf_edi; + int tf_esi; + int tf_ebp; + int tf_isp; + int tf_ebx; + int tf_edx; + int tf_ecx; + int tf_eax; + int tf_trapno; + /* below portion defined in 386 hardware */ + int tf_err; + int tf_eip; + int tf_cs; + int tf_eflags; + /* below only when transitting rings (e.g. user to kernel) */ + int tf_esp; + int tf_ss; +}; + +/* Interrupt stack frame */ + +struct intrframe { + int if_vec; + int if_ppl; + int if_es; + int if_ds; + int if_edi; + int if_esi; + int if_ebp; + int :32; + int if_ebx; + int if_edx; + int if_ecx; + int if_eax; + int :32; /* for compat with trap frame - trapno */ + int :32; /* for compat with trap frame - err */ + /* below portion defined in 386 hardware */ + int if_eip; + int if_cs; + int if_eflags; + /* below only when transitting rings (e.g. user to kernel) */ + int if_esp; + int if_ss; +}; + +/* + * Call Gate/System Call Stack Frame + */ + +struct syscframe { + int sf_edi; + int sf_esi; + int sf_ebp; + int :32; /* redundant save of isp */ + int sf_ebx; + int sf_edx; + int sf_ecx; + int sf_eax; + int sf_eflags; + /* below portion defined in 386 hardware */ +/* int sf_args[N]; /* if call gate copy args enabled!*/ + int sf_eip; + int sf_cs; + /* below only when transitting rings (e.g. user to kernel) */ + int sf_esp; + int sf_ss; +}; diff --git a/sys/amd64/include/npx.h b/sys/amd64/include/npx.h new file mode 100644 index 000000000000..134e0c12aee8 --- /dev/null +++ b/sys/amd64/include/npx.h @@ -0,0 +1,146 @@ +/*- + * 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. + * + * @(#)npx.h 5.3 (Berkeley) 1/18/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Bruce Evans New npx-0.5 code + * + */ + +/* + * 287/387 NPX Coprocessor Data Structures and Constants + * W. Jolitz 1/90 + */ + +#ifndef ___NPX87___ +#define ___NPX87___ + +/* Environment information of floating point unit */ +struct env87 { + long en_cw; /* control word (16bits) */ + long en_sw; /* status word (16bits) */ + long en_tw; /* tag word (16bits) */ + long en_fip; /* floating point instruction pointer */ + u_short en_fcs; /* floating code segment selector */ + u_short en_opcode; /* opcode last executed (11 bits ) */ + long en_foo; /* floating operand offset */ + long en_fos; /* floating operand segment selector */ +}; + +/* Contents of each floating point accumulator */ +struct fpacc87 { +#ifdef dontdef /* too unportable */ + u_long fp_mantlo; /* mantissa low (31:0) */ + u_long fp_manthi; /* mantissa high (63:32) */ + int fp_exp:15; /* exponent */ + int fp_sgn:1; /* mantissa sign */ +#else + u_char fp_bytes[10]; +#endif +}; + +/* Floating point context */ +struct save87 { + struct env87 sv_env; /* floating point control/status */ + struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */ +#ifndef dontdef + u_long sv_ex_sw; /* status word for last exception (was pad) */ + u_long sv_ex_tw; /* tag word for last exception (was pad) */ + u_char sv_pad[8 * 2 - 2 * 4]; /* bogus historical padding */ +#endif +}; + +/* Cyrix EMC memory - mapped coprocessor context switch information */ +struct emcsts { + long em_msw; /* memory mapped status register when swtched */ + long em_tar; /* memory mapped temp A register when swtched */ + long em_dl; /* memory mapped D low register when swtched */ +}; + +/* Intel prefers long real (53 bit) precision */ +#define __iBCS_NPXCW__ 0x262 +/* wfj prefers temporary real (64 bit) precision */ +#define __386BSD_NPXCW__ 0x362 +/* + * bde prefers 53 bit precision and all exceptions masked. + * + * The standard control word from finit is 0x37F, giving: + * + * round to nearest + * 64-bit precision + * all exceptions masked. + * + * Now I want: + * + * affine mode for 287's (if they work at all) (1 in bitfield 1<<12) + * 53-bit precision (2 in bitfield 3<<8) + * overflow exception unmasked (0 in bitfield 1<<3) + * zero divide exception unmasked (0 in bitfield 1<<2) + * invalid-operand exception unmasked (0 in bitfield 1<<0). + * + * 64-bit precision often gives bad results with high level languages + * because it makes the results of calculations depend on whether + * intermediate values are stored in memory or in FPU registers. + * + * The "Intel" and wfj control words have: + * + * underflow exception unmasked (0 in bitfield 1<<4) + * + * but that causes an unexpected exception in the test program 'paranoia' + * and makes denormals useless (DBL_MIN / 2 underflows). It doesn't make + * a lot of sense to trap underflow without trapping denormals. + * + * Later I will want the IEEE default of all exceptions masked. See the + * 0.0 math manpage for why this is better. The 0.1 math manpage is empty. + */ +#define __BDE_NPXCW__ 0x1272 +#define __BETTER_BDE_NPXCW__ 0x127f + +#ifdef __BROKEN_NPXCW__ +#ifdef __386BSD__ +#define __INITIAL_NPXCW__ __386BSD_NPXCW__ +#else +#define __INITIAL_NPXCW__ __iBCS_NPXCW__ +#endif +#else +#define __INITIAL_NPXCW__ __BDE_NPXCW__ +#endif + +#endif ___NPX87___ diff --git a/sys/amd64/include/pc/display.h b/sys/amd64/include/pc/display.h new file mode 100644 index 000000000000..cab46e44e881 --- /dev/null +++ b/sys/amd64/include/pc/display.h @@ -0,0 +1,43 @@ +/* + * 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 + +/* 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 + +/* 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/amd64/include/pcb.h b/sys/amd64/include/pcb.h new file mode 100644 index 000000000000..92bd810ca0df --- /dev/null +++ b/sys/amd64/include/pcb.h @@ -0,0 +1,87 @@ +/*- + * 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. + * + * @(#)pcb.h 5.10 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Bruce Evans New npx-0.5 code + * + */ + +/* + * Intel 386 process control block + */ +#include "machine/tss.h" +#include "machine/npx.h" + +struct pcb { + struct i386tss pcb_tss; +#define pcb_ksp pcb_tss.tss_esp0 +#define pcb_ptd pcb_tss.tss_cr3 +#define pcb_cr3 pcb_ptd +#define pcb_pc pcb_tss.tss_eip +#define pcb_psl pcb_tss.tss_eflags +#define pcb_usp pcb_tss.tss_esp +#define pcb_fp pcb_tss.tss_ebp +#ifdef notyet + u_char pcb_iomap[NPORT/sizeof(u_char)]; /* i/o port bitmap */ +#endif + struct save87 pcb_savefpu; /* floating point state for 287/387 */ + struct emcsts pcb_saveemc; /* Cyrix EMC state */ +/* + * Software pcb (extension) + */ + int pcb_flags; +#ifdef notused +#define FP_WASUSED 0x01 /* process has used fltng pnt hardware */ +#define FP_NEEDSSAVE 0x02 /* ... that needs save on next context switch */ +#define FP_NEEDSRESTORE 0x04 /* ... that needs restore on next DNA fault */ +#endif +#define FP_USESEMC 0x08 /* process uses EMC memory-mapped mode */ +#define FM_TRAP 0x10 /* process entered kernel on a trap frame */ +#define FP_SOFTFP 0x20 /* process using software fltng pnt emulator */ + short pcb_iml; /* interrupt mask level */ + caddr_t pcb_onfault; /* copyin/out fault recovery */ + long pcb_sigc[8]; /* XXX signal code trampoline */ + int pcb_cmap2; /* XXX temporary PTE - will prefault instead */ +}; + +#ifdef KERNEL +struct pcb *curpcb; /* our current running pcb */ +#endif diff --git a/sys/amd64/include/pmap.h b/sys/amd64/include/pmap.h new file mode 100644 index 000000000000..2eff22fa229f --- /dev/null +++ b/sys/amd64/include/pmap.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) 1991 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 William Jolitz of UUNET Technologies 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. + * + * @(#)pmap.h 7.4 (Berkeley) 5/12/91 + */ + +/* + * Derived from hp300 version by Mike Hibler, this version by William + * Jolitz uses a recursive map [a pde points to the page directory] to + * map the page tables using the pagetables themselves. This is done to + * reduce the impact on kernel virtual memory for lots of sparse address + * space, and to reduce the cost of memory to each process. + * + * from hp300: @(#)pmap.h 7.2 (Berkeley) 12/16/90 + */ + +#ifndef _PMAP_MACHINE_ +#define _PMAP_MACHINE_ 1 + +/* + * 386 page table entry and page table directory + * W.Jolitz, 8/89 + */ + +struct pde +{ +unsigned int + pd_v:1, /* valid bit */ + pd_prot:2, /* access control */ + pd_mbz1:2, /* reserved, must be zero */ + pd_u:1, /* hardware maintained 'used' bit */ + :1, /* not used */ + pd_mbz2:2, /* reserved, must be zero */ + :3, /* reserved for software */ + pd_pfnum:20; /* physical page frame number of pte's*/ +}; + +#define PD_MASK 0xffc00000 /* page directory address bits */ +#define PT_MASK 0x003ff000 /* page table address bits */ +#define PD_SHIFT 22 /* page directory address shift */ +#define PG_SHIFT 12 /* page table address shift */ + +struct pte +{ +unsigned int + pg_v:1, /* valid bit */ + pg_prot:2, /* access control */ + pg_mbz1:2, /* reserved, must be zero */ + pg_u:1, /* hardware maintained 'used' bit */ + pg_m:1, /* hardware maintained modified bit */ + pg_mbz2:2, /* reserved, must be zero */ + pg_w:1, /* software, wired down page */ + :1, /* software (unused) */ + pg_nc:1, /* 'uncacheable page' bit */ + pg_pfnum:20; /* physical page frame number */ +}; + +#define PG_V 0x00000001 +#define PG_RO 0x00000000 +#define PG_RW 0x00000002 +#define PG_u 0x00000004 +#define PG_PROT 0x00000006 /* all protection bits . */ +#define PG_W 0x00000200 +#define PG_N 0x00000800 /* Non-cacheable */ +#define PG_M 0x00000040 +#define PG_U 0x00000020 +#define PG_FRAME 0xfffff000 + +#define PG_NOACC 0 +#define PG_KR 0x00000000 +#define PG_KW 0x00000002 +#define PG_URKR 0x00000004 +#define PG_URKW 0x00000004 +#define PG_UW 0x00000006 + +/* Garbage for current bastardized pager that assumes a hp300 */ +#define PG_NV 0 +#define PG_CI 0 +/* + * Page Protection Exception bits + */ + +#define PGEX_P 0x01 /* Protection violation vs. not present */ +#define PGEX_W 0x02 /* during a Write cycle */ +#define PGEX_U 0x04 /* access from User mode (UPL) */ + +typedef struct pde pd_entry_t; /* page directory entry */ +typedef struct pte pt_entry_t; /* Mach page table entry */ + +/* + * One page directory, shared between + * kernel and user modes. + */ +#define I386_PAGE_SIZE NBPG +#define I386_PDR_SIZE NBPDR + +#define I386_KPDES 8 /* KPT page directory size */ +#define I386_UPDES NBPDR/sizeof(struct pde)-8 /* UPT page directory size */ + +#define UPTDI 0x3f6 /* ptd entry for u./kernel&user stack */ +#define PTDPTDI 0x3f7 /* ptd entry that points to ptd! */ +#define KPTDI_FIRST 0x3f8 /* start of kernel virtual pde's */ +#define KPTDI_LAST 0x3fA /* last of kernel virtual pde's */ + +/* + * Address of current and alternate address space page table maps + * and directories. + */ +#ifdef KERNEL +extern struct pte PTmap[], APTmap[], Upte; +extern struct pde PTD[], APTD[], PTDpde, APTDpde, Upde; +extern pt_entry_t *Sysmap; + +extern int IdlePTD; /* physical address of "Idle" state directory */ +#endif + +/* + * virtual address to page table entry and + * to physical address. Likewise for alternate address space. + * Note: these work recursively, thus vtopte of a pte will give + * the corresponding pde that in turn maps it. + */ +#define vtopte(va) (PTmap + i386_btop(va)) +#define kvtopte(va) vtopte(va) +#define ptetov(pt) (i386_ptob(pt - PTmap)) +#define vtophys(va) (i386_ptob(vtopte(va)->pg_pfnum) | ((int)(va) & PGOFSET)) +#define ispt(va) ((va) >= UPT_MIN_ADDRESS && (va) <= KPT_MAX_ADDRESS) + +#define avtopte(va) (APTmap + i386_btop(va)) +#define ptetoav(pt) (i386_ptob(pt - APTmap)) +#define avtophys(va) (i386_ptob(avtopte(va)->pg_pfnum) | ((int)(va) & PGOFSET)) + +/* + * macros to generate page directory/table indicies + */ + +#define pdei(va) (((va)&PD_MASK)>>PD_SHIFT) +#define ptei(va) (((va)&PT_MASK)>>PG_SHIFT) + +/* + * Pmap stuff + */ + +struct pmap { + pd_entry_t *pm_pdir; /* KVA of page directory */ + boolean_t pm_pdchanged; /* pdir changed */ + short pm_dref; /* page directory ref count */ + short pm_count; /* pmap reference count */ + simple_lock_data_t pm_lock; /* lock on pmap */ + struct pmap_statistics pm_stats; /* pmap statistics */ + long pm_ptpages; /* more stats: PT pages */ +}; + +typedef struct pmap *pmap_t; + +#ifdef KERNEL +extern pmap_t kernel_pmap; +#endif + +/* + * Macros for speed + */ +#define PMAP_ACTIVATE(pmapp, pcbp) \ + if ((pmapp) != NULL /*&& (pmapp)->pm_pdchanged */) { \ + (pcbp)->pcb_cr3 = \ + pmap_extract(kernel_pmap, (pmapp)->pm_pdir); \ + if ((pmapp) == &curproc->p_vmspace->vm_pmap) \ + load_cr3((pcbp)->pcb_cr3); \ + (pmapp)->pm_pdchanged = FALSE; \ + } + +#define PMAP_DEACTIVATE(pmapp, pcbp) + +/* + * 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. + */ +typedef struct pv_entry { + struct pv_entry *pv_next; /* next pv_entry */ + pmap_t pv_pmap; /* pmap where mapping lies */ + vm_offset_t pv_va; /* virtual address for mapping */ + int pv_flags; /* flags */ +} *pv_entry_t; + +#define PV_ENTRY_NULL ((pv_entry_t) 0) + +#define PV_CI 0x01 /* all entries must be cache inhibited */ +#define PV_PTPAGE 0x02 /* entry maps a page table page */ + +#ifdef KERNEL + +pv_entry_t pv_table; /* array of entries, one per page */ + +#define pa_index(pa) atop(pa - vm_first_phys) +#define pa_to_pvh(pa) (&pv_table[pa_index(pa)]) + +#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) + +#endif KERNEL + +#endif _PMAP_MACHINE_ diff --git a/sys/amd64/include/proc.h b/sys/amd64/include/proc.h new file mode 100644 index 000000000000..02f3c01ac3e8 --- /dev/null +++ b/sys/amd64/include/proc.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1991 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. + * + * @(#)proc.h 7.1 (Berkeley) 5/15/91 + */ + +/* + * Machine-dependent part of the proc structure for hp300. + */ +struct mdproc { + int md_flags; /* machine-dependent flags */ +#ifdef notyet + int *p_regs; /* registers on current frame */ +#endif +}; + +/* md_flags */ +#define MDP_AST 0x0001 /* async trap pending */ diff --git a/sys/amd64/include/psl.h b/sys/amd64/include/psl.h new file mode 100644 index 000000000000..aee73ed25ce2 --- /dev/null +++ b/sys/amd64/include/psl.h @@ -0,0 +1,60 @@ +/*- + * 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. + * + * @(#)psl.h 5.2 (Berkeley) 1/18/91 + */ + +/* + * 386 processor status longword. + */ +#define PSL_C 0x00000001 /* carry bit */ +#define PSL_PF 0x00000004 /* parity bit */ +#define PSL_AF 0x00000010 /* bcd carry bit */ +#define PSL_Z 0x00000040 /* zero bit */ +#define PSL_N 0x00000080 /* negative bit */ +#define PSL_T 0x00000100 /* trace enable bit */ +#define PSL_I 0x00000200 /* interrupt enable bit */ +#define PSL_D 0x00000400 /* string instruction direction bit */ +#define PSL_V 0x00000800 /* overflow bit */ +#define PSL_IOPL 0x00003000 /* i/o priviledge level enable */ +#define PSL_NT 0x00004000 /* nested task bit */ +#define PSL_RF 0x00010000 /* restart flag bit */ +#define PSL_VM 0x00020000 /* virtual 8086 mode bit */ + +#define PSL_MBZ 0xfffc7fb7 /* must be zero bits */ +#define PSL_MBO 0x00000002 /* must be one bits */ + +#define PSL_USERSET (PSL_IOPL) +#define PSL_USERCLR (PSL_I|PSL_NT) diff --git a/sys/amd64/include/reg.h b/sys/amd64/include/reg.h new file mode 100644 index 000000000000..bc2f05cf0cfe --- /dev/null +++ b/sys/amd64/include/reg.h @@ -0,0 +1,93 @@ +/*- + * 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. + * + * @(#)reg.h 5.5 (Berkeley) 1/18/91 + */ + +/* + * Location of the users' stored + * registers within appropriate frame of 'trap' and 'syscall', relative to + * base of stack frame. + * Normal usage is u.u_ar0[XX] in kernel. + */ + +/* When referenced during a trap/exception, registers are at these offsets */ + +#define tES (0) +#define tDS (1) +#define tEDI (2) +#define tESI (3) +#define tEBP (4) + +#define tEBX (6) +#define tEDX (7) +#define tECX (8) +#define tEAX (9) + +#define tEIP (12) +#define tCS (13) +#define tEFLAGS (14) +#define tESP (15) +#define tSS (16) + +/* During a system call, registers are at these offsets instead of above. */ + +#define sEDI (0) +#define sESI (1) +#define sEBP (2) + +#define sEBX (4) +#define sEDX (5) +#define sECX (6) +#define sEAX (7) +#define sEFLAGS (8) +#define sEIP (9) +#define sCS (10) +#define sESP (11) +#define sSS (12) + +#define PC sEIP +#define SP sESP +#define PS sEFLAGS +#define R0 sEDX +#define R1 sECX +/* + * Registers accessible to ptrace(2) syscall for debugger + */ +#ifdef IPCREG +#define NIPCREG 14 +int ipcreg[NIPCREG] = + { tES,tDS,tEDI,tESI,tEBP,tEBX,tEDX,tECX,tEAX,tEIP,tCS,tEFLAGS,tESP,tSS }; +#endif diff --git a/sys/amd64/include/segments.h b/sys/amd64/include/segments.h new file mode 100644 index 000000000000..0456e59ac86b --- /dev/null +++ b/sys/amd64/include/segments.h @@ -0,0 +1,196 @@ +/*- + * Copyright (c) 1989, 1990 William F. Jolitz + * 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. + * + * @(#)segments.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * 386 Segmentation Data Structures and definitions + * William F. Jolitz (william@ernie.berkeley.edu) 6/20/1989 + */ + +/* + * Selectors + */ + +#define ISPL(s) ((s)&3) /* what is the priority level of a selector */ +#define SEL_KPL 0 /* kernel priority level */ +#define SEL_UPL 3 /* user priority level */ +#define ISLDT(s) ((s)&SEL_LDT) /* is it local or global */ +#define SEL_LDT 4 /* local descriptor table */ +#define IDXSEL(s) (((s)>>3) & 0x1fff) /* index of selector */ +#define LSEL(s,r) (((s)<<3) | SEL_LDT | r) /* a local selector */ +#define GSEL(s,r) (((s)<<3) | r) /* a global selector */ + +/* + * Memory and System segment descriptors + */ +struct segment_descriptor { + unsigned sd_lolimit:16 ; /* segment extent (lsb) */ + unsigned sd_lobase:24 ; /* segment base address (lsb) */ + unsigned sd_type:5 ; /* segment type */ + unsigned sd_dpl:2 ; /* segment descriptor priority level */ + unsigned sd_p:1 ; /* segment descriptor present */ + unsigned sd_hilimit:4 ; /* segment extent (msb) */ + unsigned sd_xx:2 ; /* unused */ + unsigned sd_def32:1 ; /* default 32 vs 16 bit size */ + unsigned sd_gran:1 ; /* limit granularity (byte/page units)*/ + unsigned sd_hibase:8 ; /* segment base address (msb) */ +} ; + +/* + * Gate descriptors (e.g. indirect descriptors) + */ +struct gate_descriptor { + unsigned gd_looffset:16 ; /* gate offset (lsb) */ + unsigned gd_selector:16 ; /* gate segment selector */ + unsigned gd_stkcpy:5 ; /* number of stack wds to cpy */ + unsigned gd_xx:3 ; /* unused */ + unsigned gd_type:5 ; /* segment type */ + unsigned gd_dpl:2 ; /* segment descriptor priority level */ + unsigned gd_p:1 ; /* segment descriptor present */ + unsigned gd_hioffset:16 ; /* gate offset (msb) */ +} ; + +/* + * Generic descriptor + */ +union descriptor { + struct segment_descriptor sd; + struct gate_descriptor gd; +}; + + /* system segments and gate types */ +#define SDT_SYSNULL 0 /* system null */ +#define SDT_SYS286TSS 1 /* system 286 TSS available */ +#define SDT_SYSLDT 2 /* system local descriptor table */ +#define SDT_SYS286BSY 3 /* system 286 TSS busy */ +#define SDT_SYS286CGT 4 /* system 286 call gate */ +#define SDT_SYSTASKGT 5 /* system task gate */ +#define SDT_SYS286IGT 6 /* system 286 interrupt gate */ +#define SDT_SYS286TGT 7 /* system 286 trap gate */ +#define SDT_SYSNULL2 8 /* system null again */ +#define SDT_SYS386TSS 9 /* system 386 TSS available */ +#define SDT_SYSNULL3 10 /* system null again */ +#define SDT_SYS386BSY 11 /* system 386 TSS busy */ +#define SDT_SYS386CGT 12 /* system 386 call gate */ +#define SDT_SYSNULL4 13 /* system null again */ +#define SDT_SYS386IGT 14 /* system 386 interrupt gate */ +#define SDT_SYS386TGT 15 /* system 386 trap gate */ + + /* memory segment types */ +#define SDT_MEMRO 16 /* memory read only */ +#define SDT_MEMROA 17 /* memory read only accessed */ +#define SDT_MEMRW 18 /* memory read write */ +#define SDT_MEMRWA 19 /* memory read write accessed */ +#define SDT_MEMROD 20 /* memory read only expand dwn limit */ +#define SDT_MEMRODA 21 /* memory read only expand dwn limit accessed */ +#define SDT_MEMRWD 22 /* memory read write expand dwn limit */ +#define SDT_MEMRWDA 23 /* memory read write expand dwn limit acessed */ +#define SDT_MEME 24 /* memory execute only */ +#define SDT_MEMEA 25 /* memory execute only accessed */ +#define SDT_MEMER 26 /* memory execute read */ +#define SDT_MEMERA 27 /* memory execute read accessed */ +#define SDT_MEMEC 28 /* memory execute only conforming */ +#define SDT_MEMEAC 29 /* memory execute only accessed conforming */ +#define SDT_MEMERC 30 /* memory execute read conforming */ +#define SDT_MEMERAC 31 /* memory execute read accessed conforming */ + +/* is memory segment descriptor pointer ? */ +#define ISMEMSDP(s) ((s->d_type) >= SDT_MEMRO && (s->d_type) <= SDT_MEMERAC) + +/* is 286 gate descriptor pointer ? */ +#define IS286GDP(s) (((s->d_type) >= SDT_SYS286CGT \ + && (s->d_type) < SDT_SYS286TGT)) + +/* is 386 gate descriptor pointer ? */ +#define IS386GDP(s) (((s->d_type) >= SDT_SYS386CGT \ + && (s->d_type) < SDT_SYS386TGT)) + +/* is gate descriptor pointer ? */ +#define ISGDP(s) (IS286GDP(s) || IS386GDP(s)) + +/* is segment descriptor pointer ? */ +#define ISSDP(s) (ISMEMSDP(s) || !ISGDP(s)) + +/* is system segment descriptor pointer ? */ +#define ISSYSSDP(s) (!ISMEMSDP(s) && !ISGDP(s)) + +/* + * Software definitions are in this convenient format, + * which are translated into inconvenient segment descriptors + * when needed to be used by the 386 hardware + */ + +struct soft_segment_descriptor { + unsigned ssd_base ; /* segment base address */ + unsigned ssd_limit ; /* segment extent */ + unsigned ssd_type:5 ; /* segment type */ + unsigned ssd_dpl:2 ; /* segment descriptor priority level */ + unsigned ssd_p:1 ; /* segment descriptor present */ + unsigned ssd_xx:4 ; /* unused */ + unsigned ssd_xx1:2 ; /* unused */ + unsigned ssd_def32:1 ; /* default 32 vs 16 bit size */ + unsigned ssd_gran:1 ; /* limit granularity (byte/page units)*/ +}; + +extern ssdtosd() ; /* to decode a ssd */ +extern sdtossd() ; /* to encode a sd */ + +/* + * region descriptors, used to load gdt/idt tables before segments yet exist. + */ +struct region_descriptor { + unsigned rd_limit:16; /* segment extent */ + unsigned rd_base:32; /* base address */ +}; + +/* + * Segment Protection Exception code bits + */ + +#define SEGEX_EXT 0x01 /* recursive or externally induced */ +#define SEGEX_IDT 0x02 /* interrupt descriptor table */ +#define SEGEX_TI 0x04 /* local descriptor table */ + /* other bits are affected descriptor index */ +#define SEGEX_IDX(s) ((s)>>3)&0x1fff) + +/* + * Size of IDT table + */ + +#define NIDT 256 +#define NRSVIDT 32 /* reserved entries for cpu exceptions */ diff --git a/sys/amd64/include/specialreg.h b/sys/amd64/include/specialreg.h new file mode 100644 index 000000000000..d1908c9371b6 --- /dev/null +++ b/sys/amd64/include/specialreg.h @@ -0,0 +1,67 @@ +/*- + * 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. + * + * @(#)specialreg.h 7.1 (Berkeley) 5/9/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Bruce Evans New npx-0.5 code + * + */ + +/* + * Bits in 386 special registers: + */ + +#define CR0_PE 0x00000001 /* Protected mode Enable */ +#define CR0_MP 0x00000002 /* "Math" Present (NPX or NPX emulator) */ +#ifdef notused +#define CR0_EM 0x00000004 /* EMulate non-NPX coproc. (trap ESC only) */ +#endif +#define CR0_TS 0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */ +#ifdef notused +#define CR0_ET 0x00000010 /* Extension Type (387 (if set) vs 287) */ +#endif +#define CR0_PG 0x80000000 /* PaGing enable */ + +/* + * Bits in 486 special registers: + */ + +#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */ +#define CR0_WP 0x00010000 /* Write Protect (honor ~PG_W in all modes) */ +#ifdef notyet +#define CR0_AM 0x00040000 /* Alignment Mask (set to enable AC flag) */ +#endif diff --git a/sys/amd64/include/trap.h b/sys/amd64/include/trap.h new file mode 100644 index 000000000000..601560523d03 --- /dev/null +++ b/sys/amd64/include/trap.h @@ -0,0 +1,96 @@ +/*- + * 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. + * + * @(#)trap.h 5.4 (Berkeley) 5/9/91 + */ + +/* + * Trap type values + * also known in trap.c for name strings + */ + +#define T_RESADFLT 0 /* reserved addressing */ +#define T_PRIVINFLT 1 /* privileged instruction */ +#define T_RESOPFLT 2 /* reserved operand */ +#define T_BPTFLT 3 /* breakpoint instruction */ +#define T_SYSCALL 5 /* system call (kcall) */ +#define T_ARITHTRAP 6 /* arithmetic trap */ +#define T_ASTFLT 7 /* system forced exception */ +#define T_SEGFLT 8 /* segmentation (limit) fault */ +#define T_PROTFLT 9 /* protection fault */ +#define T_TRCTRAP 10 /* trace trap */ +#define T_PAGEFLT 12 /* page fault */ +#define T_TABLEFLT 13 /* page table fault */ +#define T_ALIGNFLT 14 /* alignment fault */ +#define T_KSPNOTVAL 15 /* kernel stack pointer not valid */ +#define T_BUSERR 16 /* bus error */ +#define T_KDBTRAP 17 /* kernel debugger trap */ + +#define T_DIVIDE 18 /* integer divide fault */ +#define T_NMI 19 /* non-maskable trap */ +#define T_OFLOW 20 /* overflow trap */ +#define T_BOUND 21 /* bound instruction fault */ +#define T_DNA 22 /* device not available fault */ +#define T_DOUBLEFLT 23 /* double fault */ +#define T_FPOPFLT 24 /* fp coprocessor operand fetch fault */ +#define T_TSSFLT 25 /* invalid tss fault */ +#define T_SEGNPFLT 26 /* segment not present fault */ +#define T_STKFLT 27 /* stack fault */ +#define T_RESERVED 28 /* reserved fault base */ + +/* definitions for <sys/signal.h> */ +#define ILL_RESAD_FAULT T_RESADFLT +#define ILL_PRIVIN_FAULT T_PRIVINFLT +#define ILL_RESOP_FAULT T_RESOPFLT +#define ILL_ALIGN_FAULT T_ALIGNFLT +#define ILL_FPOP_FAULT T_FPOPFLT /* coprocessor operand fault */ + +/* codes for SIGFPE/ARITHTRAP */ +#define FPE_INTOVF_TRAP 0x1 /* integer overflow */ +#define FPE_INTDIV_TRAP 0x2 /* integer divide by zero */ +#define FPE_FLTDIV_TRAP 0x3 /* floating/decimal divide by zero */ +#define FPE_FLTOVF_TRAP 0x4 /* floating overflow */ +#define FPE_FLTUND_TRAP 0x5 /* floating underflow */ +#define FPE_FPU_NP_TRAP 0x6 /* floating point unit not present */ +#define FPE_SUBRNG_TRAP 0x7 /* subrange out of bounds */ + +/* codes for SIGBUS */ +#define BUS_PAGE_FAULT T_PAGEFLT /* page fault protection base */ +#define BUS_SEGNP_FAULT T_SEGNPFLT /* segment not present */ +#define BUS_STK_FAULT T_STKFLT /* stack segment */ +#define BUS_SEGM_FAULT T_RESERVED /* segment protection base */ + +/* Trap's coming from user mode */ +#define T_USER 0x100 diff --git a/sys/amd64/include/tss.h b/sys/amd64/include/tss.h new file mode 100644 index 000000000000..8ba140d6c7ec --- /dev/null +++ b/sys/amd64/include/tss.h @@ -0,0 +1,78 @@ +/*- + * 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. + * + * @(#)tss.h 5.4 (Berkeley) 1/18/91 + */ + +/* + * Intel 386 Context Data Type + */ + +struct i386tss { + int tss_link; /* actually 16 bits: top 16 bits must be zero */ + int tss_esp0; /* kernel stack pointer priviledge level 0 */ +#define tss_ksp tss_esp0 + int tss_ss0; /* actually 16 bits: top 16 bits must be zero */ + int tss_esp1; /* kernel stack pointer priviledge level 1 */ + int tss_ss1; /* actually 16 bits: top 16 bits must be zero */ + int tss_esp2; /* kernel stack pointer priviledge level 2 */ + int tss_ss2; /* actually 16 bits: top 16 bits must be zero */ + /* struct ptd *tss_cr3; /* page table directory */ + int tss_cr3; /* page table directory */ +#define tss_ptd tss_cr3 + int tss_eip; /* program counter */ +#define tss_pc tss_eip + int tss_eflags; /* program status longword */ +#define tss_psl tss_eflags + int tss_eax; + int tss_ecx; + int tss_edx; + int tss_ebx; + int tss_esp; /* user stack pointer */ +#define tss_usp tss_esp + int tss_ebp; /* user frame pointer */ +#define tss_fp tss_ebp + int tss_esi; + int tss_edi; + int tss_es; /* actually 16 bits: top 16 bits must be zero */ + int tss_cs; /* actually 16 bits: top 16 bits must be zero */ + int tss_ss; /* actually 16 bits: top 16 bits must be zero */ + int tss_ds; /* actually 16 bits: top 16 bits must be zero */ + int tss_fs; /* actually 16 bits: top 16 bits must be zero */ + int tss_gs; /* actually 16 bits: top 16 bits must be zero */ + int tss_ldt; /* actually 16 bits: top 16 bits must be zero */ + int tss_ioopt; /* options & io offset bitmap: currently zero */ + /* XXX unimplemented .. i/o permission bitmap */ +}; diff --git a/sys/amd64/include/vmparam.h b/sys/amd64/include/vmparam.h new file mode 100644 index 000000000000..39403d6aba6e --- /dev/null +++ b/sys/amd64/include/vmparam.h @@ -0,0 +1,256 @@ +/*- + * 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. + * + * @(#)vmparam.h 5.9 (Berkeley) 5/12/91 + */ + + +/* + * Machine dependent constants for 386. + */ + +/* + * Virtual address space arrangement. On 386, both user and kernel + * share the address space, not unlike the vax. + * USRTEXT is the start of the user text/data space, while USRSTACK + * is the top (end) of the user stack. Immediately above the user stack + * resides the user structure, which is UPAGES long and contains the + * kernel stack. + * + * Immediately after the user structure is the page table map, and then + * kernal address space. + */ +#define USRTEXT 0 +#define USRSTACK 0xFDBFE000 +#define BTOPUSRSTACK (0xFDC00-(UPAGES)) /* btop(USRSTACK) */ +#define LOWPAGES 0 +#define HIGHPAGES UPAGES + +/* + * Virtual memory related constants, all in bytes + */ +#define MAXTSIZ (6*1024*1024) /* max text size */ +#ifndef DFLDSIZ +#define DFLDSIZ (6*1024*1024) /* initial data size limit */ +#endif +#ifndef MAXDSIZ +#define MAXDSIZ (32*1024*1024) /* max data size */ +#endif +#ifndef DFLSSIZ +#define DFLSSIZ (512*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. + */ +#define DMMIN 32 /* smallest swap allocation */ +#define DMMAX 4096 /* largest potential swap allocation */ +#define DMTEXT 1024 /* swap allocation for text */ + +/* + * Sizes of the system and user portions of the system page table. + */ +#define SYSPTSIZE (2*NPTEPG) +#define USRPTSIZE (2*NPTEPG) + +/* + * Size of User Raw I/O map + */ +#define USRIOSIZE 300 + +/* + * 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. + * { wfj 6/16/89: Retail AT memory expansion $800/megabyte, loan of $17 + * on disk costing $7/mb or $0.18 (in memory still 100:1 in cost!) } + */ +#define SAFERSS 8 /* 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 KLMAX*CLSIZE must be <= DMMIN in dmap.h. + */ + +#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) + +/* + * 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 + * minfree is 64k bytes, but at most 1/2 of desfree + */ +#define LOTSFREE (512 * 1024) +#define LOTSFREEFRACT 4 +#define DESFREE (200 * 1024) +#define DESFREEFRACT 8 +#define MINFREE (64 * 1024) +#define MINFREEFRACT 2 + +/* + * 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)<<PGSHIFT) | (prot)) ; } + +/* + * Mach derived constants + */ + +/* user/kernel map constants */ +#define VM_MIN_ADDRESS ((vm_offset_t)0) +#define VM_MAXUSER_ADDRESS ((vm_offset_t)0xFDBFE000) +#define UPT_MIN_ADDRESS ((vm_offset_t)0xFDC00000) +#define UPT_MAX_ADDRESS ((vm_offset_t)0xFDFF7000) +#define VM_MAX_ADDRESS UPT_MAX_ADDRESS +#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)0xFDFF7000) +#define UPDT VM_MIN_KERNEL_ADDRESS +#define KPT_MIN_ADDRESS ((vm_offset_t)0xFDFF8000) +#define KPT_MAX_ADDRESS ((vm_offset_t)0xFDFFF000) +#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t)0xFF7FF000) + +/* 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) + +/* # of kernel PT pages (initial only, can grow dynamically) */ +#define VM_KERNEL_PT_PAGES ((vm_size_t)2) /* XXX: SYSPTSIZE */ + +/* pcb base */ +#define pcbb(p) ((u_int)(p)->p_addr) + +/* + * Flush MMU TLB + */ + +#ifndef I386_CR3PAT +#define I386_CR3PAT 0x0 +#endif + +#ifdef notyet +#define _cr3() ({u_long rtn; \ + asm (" movl %%cr3,%%eax; movl %%eax,%0 " \ + : "=g" (rtn) \ + : \ + : "ax"); \ + rtn; \ +}) + +#define load_cr3(s) ({ u_long val; \ + val = (s) | I386_CR3PAT; \ + asm ("movl %0,%%eax; movl %%eax,%%cr3" \ + : \ + : "g" (val) \ + : "ax"); \ +}) + +#define tlbflush() ({ u_long val; \ + val = u.u_pcb.pcb_ptd | I386_CR3PAT; \ + asm ("movl %0,%%eax; movl %%eax,%%cr3" \ + : \ + : "g" (val) \ + : "ax"); \ +}) +#endif diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c new file mode 100644 index 000000000000..0fb77012d090 --- /dev/null +++ b/sys/amd64/isa/clock.c @@ -0,0 +1,271 @@ +/*- + * 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. + * + * @(#)clock.c 7.2 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 5 00158 + * -------------------- ----- ---------------------- + * + * 14 Aug 92 Arne Henrik Juul Added code in the kernel to + * allow for DST in the BIOS. + * 17 Jan 93 Bruce Evans Fixed leap year and second + * calculations + * 01 Feb 93 Julian Elischer Added code to for the cpu + * speed independent spinwait() + * function, (used by scsi and others) + * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1 + * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock + * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait + * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I + * still kept the other fixes... Had to + * add back in findcpuspeed that Bruce + * had removed. + */ + +/* + * Primitive clock interrupt routines. + */ +#include "param.h" +#include "systm.h" +#include "time.h" +#include "kernel.h" +#include "machine/segments.h" +#include "i386/isa/icu.h" +#include "i386/isa/isa.h" +#include "i386/isa/rtc.h" +#include "i386/isa/timerreg.h" + +#define DAYST 119 +#define DAYEN 303 + +/* X-tals being what they are, it's nice to be able to fudge this one... */ +/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */ +#ifndef TIMER_FREQ +#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */ +#endif + +startrtclock() { + int s; + + findcpuspeed(); /* use the clock (while it's free) + to find the cpu speed */ + /* initialize 8253 clock */ + outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); + + /* Correct rounding will buy us a better precision in timekeeping */ + outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz); + outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256); + + /* initialize brain-dead battery powered clock */ + outb (IO_RTC, RTC_STATUSA); + outb (IO_RTC+1, 0x26); + outb (IO_RTC, RTC_STATUSB); + outb (IO_RTC+1, 2); + + outb (IO_RTC, RTC_DIAG); + if (s = inb (IO_RTC+1)) + printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); + outb (IO_RTC, RTC_DIAG); + outb (IO_RTC+1, 0); +} + +unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ + +#define FIRST_GUESS 0x2000 +findcpuspeed() +{ + unsigned char low; + unsigned int remainder; + + /* Put counter in count down mode */ + outb(IO_TIMER1+3, 0x34); + outb(IO_TIMER1, 0xff); + outb(IO_TIMER1, 0xff); + delaycount = FIRST_GUESS; + spinwait(1); + /* Read the value left in the counter */ + low = inb(IO_TIMER1); /* least siginifcant */ + remainder = inb(IO_TIMER1); /* most significant */ + remainder = (remainder<<8) + low ; + /* Formula for delaycount is : + * (loopcount * timer clock speed)/ (counter ticks * 1000) + */ + delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder); +} + + +/* convert 2 digit BCD number */ +bcd(i) +int i; +{ + return ((i/16)*10 + (i%16)); +} + +/* convert years to seconds (from 1970) */ +unsigned long +ytos(y) +int y; +{ + int i; + unsigned long ret; + + ret = 0; + for(i = 1970; i < y; i++) { + if (i % 4) ret += 365*24*60*60; + else ret += 366*24*60*60; + } + return ret; +} + +/* convert months to seconds */ +unsigned long +mtos(m,leap) +int m,leap; +{ + int i; + unsigned long ret; + + ret = 0; + for(i=1;i<m;i++) { + switch(i){ + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + ret += 31*24*60*60; break; + case 4: case 6: case 9: case 11: + ret += 30*24*60*60; break; + case 2: + if (leap) ret += 29*24*60*60; + else ret += 28*24*60*60; + } + } + return ret; +} + + +/* + * Initialize the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +inittodr(base) + time_t base; +{ + unsigned long sec; + int leap,day_week,t,yd; + int sa,s; + + /* do we have a realtime clock present? (otherwise we loop below) */ + sa = rtcin(RTC_STATUSA); + if (sa == 0xff || sa == 0) return; + + /* ready for a read? */ + while ((sa&RTCSA_TUP) == RTCSA_TUP) + sa = rtcin(RTC_STATUSA); + + sec = bcd(rtcin(RTC_YEAR)) + 1900; + if (sec < 1970) + sec += 100; + leap = !(sec % 4); sec = ytos(sec); /* year */ + yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */ + t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */ + day_week = rtcin(RTC_WDAY); /* day */ + sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */ + sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */ + sec += bcd(rtcin(RTC_SEC)); /* seconds */ + + /* XXX off by one? Need to calculate DST on SUNDAY */ + /* Perhaps we should have the RTC hold GMT time to save */ + /* us the bother of converting. */ + yd = yd / (24*60*60); + if ((yd >= DAYST) && ( yd <= DAYEN)) { + sec -= 60*60; + } + sec += tz.tz_minuteswest * 60; + + time.tv_sec = sec; +} + +#ifdef garbage +/* + * Initialze the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +test_inittodr(base) + time_t base; +{ + + outb(IO_RTC,9); /* year */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,8); /* month */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,7); /* day */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,4); /* hour */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,2); /* minutes */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,0); /* seconds */ + printf("%d\n",bcd(inb(IO_RTC+1))); + + time.tv_sec = base; +} +#endif + +/* + * Restart the clock. + */ +resettodr() +{ +} + +/* + * Wire clock interrupt in. + */ +#define V(s) __CONCAT(V, s) +extern V(clk)(); +enablertclock() { + setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); + INTREN(IRQ0); +} + +/* + * Delay for some number of milliseconds. + */ +void +spinwait(millisecs) + int millisecs; +{ + DELAY(1000 * millisecs); +} diff --git a/sys/amd64/isa/icu.h b/sys/amd64/isa/icu.h new file mode 100644 index 000000000000..4866d8d0a822 --- /dev/null +++ b/sys/amd64/isa/icu.h @@ -0,0 +1,109 @@ +/*- + * 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. + * + * @(#)icu.h 5.6 (Berkeley) 5/9/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00158 + * -------------------- ----- ---------------------- + * + * 25 Apr 93 Bruce Evans New fast interrupt code (intr-0.1) + */ + +/* + * AT/386 Interrupt Control constants + * W. Jolitz 8/89 + */ + +#ifndef __ICU__ +#define __ICU__ + +#ifndef LOCORE + +/* + * Interrupt "level" mechanism variables, masks, and macros + */ +extern unsigned imen; /* interrupt mask enable */ +extern unsigned cpl; /* current priority level mask */ + +extern unsigned highmask; /* group of interrupts masked with splhigh() */ +extern unsigned ttymask; /* group of interrupts masked with spltty() */ +extern unsigned biomask; /* group of interrupts masked with splbio() */ +extern unsigned netmask; /* group of interrupts masked with splimp() */ + +#define INTREN(s) (imen &= ~(s), SET_ICUS()) +#define INTRDIS(s) (imen |= (s), SET_ICUS()) +#define INTRMASK(msk,s) (msk |= (s)) +#if 0 +#define SET_ICUS() (outb(IO_ICU1 + 1, imen), outb(IU_ICU2 + 1, imen >> 8)) +#else +/* + * XXX - IO_ICU* are defined in isa.h, not icu.h, and nothing much bothers to + * include isa.h, while too many things include icu.h. + */ +#define SET_ICUS() (outb(0x21, imen), outb(0xa1, imen >> 8)) +#endif + +#endif + +/* + * Interrupt enable bits -- in order of priority + */ +#define IRQ0 0x0001 /* highest priority - timer */ +#define IRQ1 0x0002 +#define IRQ_SLAVE 0x0004 +#define IRQ8 0x0100 +#define IRQ9 0x0200 +#define IRQ2 IRQ9 +#define IRQ10 0x0400 +#define IRQ11 0x0800 +#define IRQ12 0x1000 +#define IRQ13 0x2000 +#define IRQ14 0x4000 +#define IRQ15 0x8000 +#define IRQ3 0x0008 +#define IRQ4 0x0010 +#define IRQ5 0x0020 +#define IRQ6 0x0040 +#define IRQ7 0x0080 /* lowest - parallel printer */ + +/* + * Interrupt Control offset into Interrupt descriptor table (IDT) + */ +#define ICU_OFFSET 32 /* 0-31 are processor exceptions */ +#define ICU_LEN 16 /* 32-47 are ISA interrupts */ + +#endif __ICU__ diff --git a/sys/amd64/isa/isa.c b/sys/amd64/isa/isa.c new file mode 100644 index 000000000000..8707b43d4c68 --- /dev/null +++ b/sys/amd64/isa/isa.c @@ -0,0 +1,766 @@ +/*- + * Copyright (c) 1991 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. + * + * @(#)isa.c 7.2 (Berkeley) 5/13/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 4 00163 + * -------------------- ----- ---------------------- + * + * 18 Aug 92 Frank Maclachlan *See comments below + * 25 Mar 93 Rodney W. Grimes Added counter for stray interrupt, + * turned on logging of stray interrupts, + * Now prints maddr, msize, and flags + * after finding a device. + * 26 Apr 93 Bruce Evans New intr-0.1 code + * Rodney W. Grimes Only print io address if id_alive != -1 + * 17 May 93 Rodney W. Grimes renamed stray interrupt counters to + * work with new intr-0.1 code. + * Enabled printf for interrupt masks to + * aid in bug reports. + * 27 May 93 Guido van Rooij New routine add find_isa_dev + */ +static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/isa/RCS/isa.c,v 1.2 92/01/21 14:34:23 william Exp Locker: root $"; + +/* + * code to manage AT bus + * + * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com): + * Fixed uninitialized variable problem and added code to deal + * with DMA page boundaries in isa_dmarangecheck(). Fixed word + * mode DMA count compution and reorganized DMA setup code in + * isa_dmastart() + */ + +#include "param.h" +#include "systm.h" +#include "conf.h" +#include "file.h" +#include "buf.h" +#include "uio.h" +#include "syslog.h" +#include "malloc.h" +#include "rlist.h" +#include "machine/segments.h" +#include "vm/vm.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/isa.h" +#include "i386/isa/icu.h" +#include "i386/isa/ic/i8237.h" +#include "i386/isa/ic/i8042.h" + +/* +** Register definitions for DMA controller 1 (channels 0..3): +*/ +#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */ +#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */ +#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */ +#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */ + +/* +** Register definitions for DMA controller 2 (channels 4..7): +*/ +#define DMA2_CHN(c) (IO_DMA1 + 2*(2*(c))) /* addr reg for channel c */ +#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */ +#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */ +#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */ + +int config_isadev __P((struct isa_device *, u_int *)); + +#ifdef notyet +struct rlist *isa_iomem; + +/* + * Configure all ISA devices + */ +isa_configure() { + struct isa_device *dvp; + struct isa_driver *dp; + + splhigh(); + INTREN(IRQ_SLAVE); + /*rlist_free(&isa_iomem, 0xa0000, 0xfffff);*/ + for (dvp = isa_devtab_tty; dvp; dvp++) + (void) config_isadev(dvp, &ttymask); + for (dvp = isa_devtab_bio; dvp; dvp++) + (void) config_isadev(dvp, &biomask); + for (dvp = isa_devtab_net; dvp; dvp++) + (void) config_isadev(dvp, &netmask); + for (dvp = isa_devtab_null; dvp; dvp++) + (void) config_isadev(dvp, (u_int *) NULL); +#include "sl.h" +#if NSL > 0 + netmask |= ttymask; + ttymask |= netmask; +#endif +/* printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask); */ + splnone(); +} + +/* + * Configure an ISA device. + */ +config_isadev(isdp, mp) + struct isa_device *isdp; + u_int *mp; +{ + struct isa_driver *dp; + static short drqseen, irqseen; + + if (dp = isdp->id_driver) { + /* if a device with i/o memory, convert to virtual address */ + if (isdp->id_maddr) { + extern unsigned int atdevbase; + + isdp->id_maddr -= IOM_BEGIN; + isdp->id_maddr += atdevbase; + } + isdp->id_alive = (*dp->probe)(isdp); + if (isdp->id_alive) { + + printf("%s%d at port 0x%x ", dp->name, + isdp->id_unit, isdp->id_iobase); + + /* check for conflicts */ + if (irqseen & isdp->id_irq) { + printf("INTERRUPT CONFLICT - irq%d\n", + ffs(isdp->id_irq) - 1); + return (0); + } + if (isdp->id_drq != -1 + && (drqseen & (1<<isdp->id_drq))) { + printf("DMA CONFLICT - drq%d\n", isdp->id_drq); + return (0); + } + /* NEED TO CHECK IOMEM CONFLICT HERE */ + + /* allocate and wire in device */ + if(isdp->id_irq) { + int intrno; + + intrno = ffs(isdp->id_irq)-1; + printf("irq %d ", intrno); + INTREN(isdp->id_irq); + if(mp)INTRMASK(*mp,isdp->id_irq); + setidt(NRSVIDT + intrno, isdp->id_intr, + SDT_SYS386IGT, SEL_KPL); + irqseen |= isdp->id_irq; + } + if (isdp->id_drq != -1) { + printf("drq %d ", isdp->id_drq); + drqseen |= 1 << isdp->id_drq; + } + + (*dp->attach)(isdp); + + printf("on isa\n"); + } + return (1); + } else return(0); +} +#else /* notyet */ +/* + * Configure all ISA devices + */ +isa_configure() { + struct isa_device *dvp; + struct isa_driver *dp; + + enable_intr(); + splhigh(); + INTREN(IRQ_SLAVE); + for (dvp = isa_devtab_tty; config_isadev(dvp,&ttymask); dvp++); + for (dvp = isa_devtab_bio; config_isadev(dvp,&biomask); dvp++); + for (dvp = isa_devtab_net; config_isadev(dvp,&netmask); dvp++); + for (dvp = isa_devtab_null; config_isadev(dvp,(u_int *) NULL); dvp++); +#include "sl.h" +#if NSL > 0 + netmask |= ttymask; + ttymask |= netmask; +#endif + /* biomask |= ttymask ; can some tty devices use buffers? */ + printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask); + splnone(); +} + +/* + * Configure an ISA device. + */ +config_isadev(isdp, mp) + struct isa_device *isdp; + u_int *mp; +{ + struct isa_driver *dp; + + if (dp = isdp->id_driver) { + if (isdp->id_maddr) { + extern u_int atdevbase; + + isdp->id_maddr -= 0xa0000; /* XXX should be a define */ + isdp->id_maddr += atdevbase; + } + isdp->id_alive = (*dp->probe)(isdp); + if (isdp->id_alive) { + printf("%s%d", dp->name, isdp->id_unit); + /* + * The attach should really be after all the printf's + * but until all the drivers are fixed do it here. + * There is a comment below that shows where this + * really belongs. Rod Grimes 04/10/93 + */ + (*dp->attach)(isdp); + /* + * Only print the I/O address range if id_alive != -1 + * Right now this is a temporary fix just for the new + * NPX code so that if it finds a 486 that can use trap + * 16 it will not report I/O addresses. + * Rod Grimes 04/26/94 + */ + if (isdp->id_alive != -1) { + printf(" at 0x%x", isdp->id_iobase); + if ((isdp->id_iobase + isdp->id_alive - 1) != + isdp->id_iobase) + printf("-0x%x", + isdp->id_iobase + + isdp->id_alive - 1); + } + if(isdp->id_irq) + printf(" irq %d", ffs(isdp->id_irq)-1); + if (isdp->id_drq != -1) + printf(" drq %d", isdp->id_drq); + if (isdp->id_maddr != 0) + printf(" maddr 0x%x", kvtop(isdp->id_maddr)); + if (isdp->id_msize != 0) + printf(" msize %d", isdp->id_msize); + if (isdp->id_flags != 0) + printf(" flags 0x%x", isdp->id_flags); + printf(" on isa\n"); + + /* This is the place the attach should be done! */ + if(isdp->id_irq) { + int intrno; + + intrno = ffs(isdp->id_irq)-1; + setidt(ICU_OFFSET+intrno, isdp->id_intr, + SDT_SYS386IGT, SEL_KPL); + if(mp) + INTRMASK(*mp,isdp->id_irq); + INTREN(isdp->id_irq); + } + } + return (1); + } else return(0); +} +#endif /* (!) notyet */ + +#define IDTVEC(name) __CONCAT(X,name) +/* default interrupt vector table entries */ +extern IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3), + IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7), + IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11), + IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15); + +static *defvec[16] = { + &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3), + &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7), + &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11), + &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) }; + +/* out of range default interrupt vector gate entry */ +extern IDTVEC(intrdefault); + +/* + * Fill in default interrupt table (in case of spuruious interrupt + * during configuration of kernel, setup interrupt control unit + */ +isa_defaultirq() { + int i; + + /* icu vectors */ + for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++) + setidt(i, defvec[i], SDT_SYS386IGT, SEL_KPL); + + /* out of range vectors */ + for (i = NRSVIDT; i < NIDT; i++) + setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL); + + /* initialize 8259's */ + outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ + outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */ + outb(IO_ICU1+1, 1<<2); /* slave on line 2 */ +#ifdef AUTO_EOI_1 + outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */ +#else + outb(IO_ICU1+1, 1); /* 8086 mode */ +#endif + outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ + outb(IO_ICU1, 0x0a); /* default to IRR on read */ + outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ + + outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ + outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */ + outb(IO_ICU2+1,2); /* my slave id is 2 */ +#ifdef AUTO_EOI_2 + outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */ +#else + outb(IO_ICU2+1,1); /* 8086 mode */ +#endif + outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ + outb(IO_ICU2, 0x0a); /* default to IRR on read */ +} + +/* region of physical memory known to be contiguous */ +vm_offset_t isaphysmem; +static caddr_t dma_bounce[8]; /* XXX */ +static char bounced[8]; /* XXX */ +#define MAXDMASZ 512 /* XXX */ + +/* high byte of address is stored in this port for i-th dma channel */ +static short dmapageport[8] = + { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; + +/* + * isa_dmacascade(): program 8237 DMA controller channel to accept + * external dma control by a board. + */ +void isa_dmacascade(unsigned chan) +{ + if (chan > 7) + panic("isa_dmacascade: impossible request"); + + /* set dma channel mode, and set dma channel mode */ + if ((chan & 4) == 0) { + outb(DMA1_MODE, DMA37MD_CASCADE | chan); + outb(DMA1_SMSK, chan); + } else { + outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3)); + outb(DMA2_SMSK, chan & 3); + } +} + +/* + * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment + * problems by using a bounce buffer. + */ +void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan) +{ vm_offset_t phys; + int waport; + caddr_t newaddr; + + if ( chan > 7 + || (chan < 4 && nbytes > (1<<16)) + || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1))) + panic("isa_dmastart: impossible request"); + + if (isa_dmarangecheck(addr, nbytes, chan)) { + if (dma_bounce[chan] == 0) + dma_bounce[chan] = + /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/ + (caddr_t) isaphysmem + NBPG*chan; + bounced[chan] = 1; + newaddr = dma_bounce[chan]; + *(int *) newaddr = 0; /* XXX */ + + /* copy bounce buffer on write */ + if (!(flags & B_READ)) + bcopy(addr, newaddr, nbytes); + addr = newaddr; + } + + /* translate to physical */ + phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr); + + if ((chan & 4) == 0) { + /* + * Program one of DMA channels 0..3. These are + * byte mode channels. + */ + /* set dma channel mode, and reset address ff */ + if (flags & B_READ) + outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan); + else + outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan); + outb(DMA1_FFC, 0); + + /* send start address */ + waport = DMA1_CHN(chan); + outb(waport, phys); + outb(waport, phys>>8); + outb(dmapageport[chan], phys>>16); + + /* send count */ + outb(waport + 1, --nbytes); + outb(waport + 1, nbytes>>8); + + /* unmask channel */ + outb(DMA1_SMSK, chan); + } else { + /* + * Program one of DMA channels 4..7. These are + * word mode channels. + */ + /* set dma channel mode, and reset address ff */ + if (flags & B_READ) + outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3)); + else + outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3)); + outb(DMA2_FFC, 0); + + /* send start address */ + waport = DMA2_CHN(chan - 4); + outb(waport, phys>>1); + outb(waport, phys>>9); + outb(dmapageport[chan], phys>>16); + + /* send count */ + nbytes >>= 1; + outb(waport + 2, --nbytes); + outb(waport + 2, nbytes>>8); + + /* unmask channel */ + outb(DMA2_SMSK, chan & 3); + } +} + +void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan) +{ + + /* copy bounce buffer on read */ + /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/ + if (bounced[chan]) { + bcopy(dma_bounce[chan], addr, nbytes); + bounced[chan] = 0; + } +} + +/* + * Check for problems with the address range of a DMA transfer + * (non-contiguous physical pages, outside of bus address space, + * crossing DMA page boundaries). + * Return true if special handling needed. + */ + +isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) { + vm_offset_t phys, priorpage = 0, endva; + u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1); + + endva = (vm_offset_t)round_page(va + length); + for (; va < (caddr_t) endva ; va += NBPG) { + phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va)); +#define ISARAM_END RAM_END + if (phys == 0) + panic("isa_dmacheck: no physical page present"); + if (phys > ISARAM_END) + return (1); + if (priorpage) { + if (priorpage + NBPG != phys) + return (1); + /* check if crossing a DMA page boundary */ + if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk) + return (1); + } + priorpage = phys; + } + return (0); +} + +/* head of queue waiting for physmem to become available */ +struct buf isa_physmemq; + +/* blocked waiting for resource to become free for exclusive use */ +static isaphysmemflag; +/* if waited for and call requested when free (B_CALL) */ +static void (*isaphysmemunblock)(); /* needs to be a list */ + +/* + * Allocate contiguous physical memory for transfer, returning + * a *virtual* address to region. May block waiting for resource. + * (assumed to be called at splbio()) + */ +caddr_t +isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) { + + isaphysmemunblock = func; + while (isaphysmemflag & B_BUSY) { + isaphysmemflag |= B_WANTED; + sleep(&isaphysmemflag, PRIBIO); + } + isaphysmemflag |= B_BUSY; + + return((caddr_t)isaphysmem); +} + +/* + * Free contiguous physical memory used for transfer. + * (assumed to be called at splbio()) + */ +void +isa_freephysmem(caddr_t va, unsigned length) { + + isaphysmemflag &= ~B_BUSY; + if (isaphysmemflag & B_WANTED) { + isaphysmemflag &= B_WANTED; + wakeup(&isaphysmemflag); + if (isaphysmemunblock) + (*isaphysmemunblock)(); + } +} + +/* + * Handle a NMI, possibly a machine check. + * return true to panic system, false to ignore. + */ +isa_nmi(cd) { + + log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70)); + return(0); +} + +/* + * Caught a stray interrupt, notify + */ +isa_strayintr(d) { + + /* DON'T BOTHER FOR NOW! */ + /* for some reason, we get bursts of intr #7, even if not enabled! */ + /* + * Well the reason you got bursts of intr #7 is because someone + * raised an interrupt line and dropped it before the 8259 could + * prioritize it. This is documented in the intel data book. This + * means you have BAD hardware! I have changed this so that only + * the first 5 get logged, then it quits logging them, and puts + * out a special message. rgrimes 3/25/1993 + */ + extern u_long intrcnt_stray; + + intrcnt_stray++; + if (intrcnt_stray <= 5) + log(LOG_ERR,"ISA strayintr %x\n", d); + if (intrcnt_stray == 5) + log(LOG_CRIT,"Too many ISA strayintr not logging any more\n"); +} + +/* + * Wait "n" microseconds. + * Relies on timer 1 counting down from (TIMER_FREQ / hz) at + * (2 * TIMER_FREQ) Hz. + * Note: timer had better have been programmed before this is first used! + * (The standard programming causes the timer to generate a square wave and + * the counter is decremented twice every cycle.) + */ +#define CF (2 * TIMER_FREQ) +#define TIMER_FREQ 1193182 /* XXX - should be elsewhere */ + +extern int hz; /* XXX - should be elsewhere */ + +int DELAY(n) + int n; +{ + int counter_limit; + int prev_tick; + int tick; + int ticks_left; + int sec; + int usec; + +#ifdef DELAYDEBUG + int getit_calls = 1; + int n1; + static int state = 0; + + if (state == 0) { + state = 1; + for (n1 = 1; n1 <= 10000000; n1 *= 10) + DELAY(n1); + state = 2; + } + if (state == 1) + printf("DELAY(%d)...", n); +#endif + + /* + * Read the counter first, so that the rest of the setup overhead is + * counted. Guess the initial overhead is 20 usec (on most systems it + * takes about 1.5 usec for each of the i/o's in getit(). The loop + * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The + * multiplications and divisions to scale the count take a while). + */ + prev_tick = getit(0, 0); + n -= 20; + + /* + * Calculate (n * (CF / 1e6)) without using floating point and without + * any avoidable overflows. + */ + sec = n / 1000000; + usec = n - sec * 1000000; + ticks_left = sec * CF + + usec * (CF / 1000000) + + usec * ((CF % 1000000) / 1000) / 1000 + + usec * (CF % 1000) / 1000000; + + counter_limit = TIMER_FREQ / hz; + while (ticks_left > 0) { + tick = getit(0, 0); +#ifdef DELAYDEBUG + ++getit_calls; +#endif + if (tick > prev_tick) + ticks_left -= prev_tick - (tick - counter_limit); + else + ticks_left -= prev_tick - tick; + prev_tick = tick; + } +#ifdef DELAYDEBUG + if (state == 1) + printf(" %d calls to getit() at %d usec each\n", + getit_calls, (n + 5) / getit_calls); +#endif +} + +getit(unit, timer) { + int high; + int low; + + /* + * XXX - isa.h defines bogus timers. There's no such timer as + * IO_TIMER_2 = 0x48. There's a timer in the CMOS RAM chip but + * its interface is quite different. Neither timer is an 8252. + * We actually only call this with unit = 0 and timer = 0. It + * could be static... + */ + /* + * Protect ourself against interrupts. + * XXX - sysbeep() and sysbeepstop() need protection. + */ + disable_intr(); + /* + * Latch the count for 'timer' (cc00xxxx, c = counter, x = any). + */ + outb(IO_TIMER1 + 3, timer << 6); + + low = inb(IO_TIMER1 + timer); + high = inb(IO_TIMER1 + timer); + enable_intr(); + return ((high << 8) | low); +} + +static beeping; +static +sysbeepstop(f) +{ + /* disable counter 2 */ + outb(0x61, inb(0x61) & 0xFC); + if (f) + timeout(sysbeepstop, 0, f); + else + beeping = 0; +} + +void sysbeep(int pitch, int period) +{ + + outb(0x61, inb(0x61) | 3); /* enable counter 2 */ + /* + * XXX - move timer stuff to clock.c. + * Program counter 2: + * ccaammmb, c counter, a = access, m = mode, b = BCD + * 1011x110, 11 for aa = LSB then MSB, x11 for mmm = square wave. + */ + outb(0x43, 0xb6); /* set command for counter 2, 2 byte write */ + + outb(0x42, pitch); + outb(0x42, (pitch>>8)); + + if (!beeping) { + beeping = period; + timeout(sysbeepstop, period/2, period); + } +} + +/* + * Pass command to keyboard controller (8042) + */ +unsigned kbc_8042cmd(val) { + + while (inb(KBSTATP)&KBS_IBF); + if (val) outb(KBCMDP, val); + while (inb(KBSTATP)&KBS_IBF); + return (inb(KBDATAP)); +} + +/* + * find an ISA device in a given isa_devtab_* table, given + * the table to search, the expected id_driver entry, and the unit number. + * + * this function is defined in isa_device.h, and this location is debatable; + * i put it there because it's useless w/o, and directly operates on + * the other stuff in that file. + * + */ + +struct isa_device *find_isadev(table, driverp, unit) + struct isa_device *table; + struct isa_driver *driverp; + int unit; +{ + if (driverp == NULL) /* sanity check */ + return NULL; + + while ((table->id_driver != driverp) || (table->id_unit != unit)) { + if (table->id_driver == 0) + return NULL; + + table++; + } + + return table; +} + +/* + * Return nonzero if a (masked) irq is pending for a given device. + */ +int +isa_irq_pending(dvp) + struct isa_device *dvp; +{ + unsigned id_irq; + + id_irq = (unsigned short) dvp->id_irq; /* XXX silly type in struct */ + if (id_irq & 0xff) + return (inb(IO_ICU1) & id_irq); + return (inb(IO_ICU2) & (id_irq >> 8)); +} diff --git a/sys/amd64/isa/isa.h b/sys/amd64/isa/isa.h new file mode 100644 index 000000000000..a9c042d4e542 --- /dev/null +++ b/sys/amd64/isa/isa.h @@ -0,0 +1,188 @@ +/*- + * 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. + * + * @(#)isa.h 5.7 (Berkeley) 5/9/91 + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 3 00158 + * -------------------- ----- ---------------------- + * + * 15 Feb 93 Julian Elischer Added entries for some scsi adapters + * 06 Apr 93 Rodney W. Grimes Added com3 and com4, added IO_ISASIZES + * section + * 26 Apr 93 Bruce Evans Support for intr-0.1 + */ + +/* + * ISA Bus conventions + */ + +#ifndef LOCORE +#include <sys/cdefs.h> + +unsigned char rtcin __P((int)); +extern unsigned int atdevbase; /* offset in virtual memory of ISA io mem */ +void sysbeep __P((int, int)); +unsigned kbd_8042cmd __P((int)); +struct isa_device; +int isa_irq_pending __P((struct isa_device *dvp)); +#endif + + +/* + * Input / Output Port Assignments + */ + +#ifndef IO_BEGIN +#define IO_ISABEGIN 0x000 /* 0x000 - Beginning of I/O Registers */ + + /* CPU Board */ +#define IO_DMA1 0x000 /* 8237A DMA Controller #1 */ +#define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */ +#define IO_TIMER1 0x040 /* 8252 Timer #1 */ +#define IO_TIMER2 0x048 /* 8252 Timer #2 */ +#define IO_KBD 0x060 /* 8042 Keyboard */ +#define IO_RTC 0x070 /* RTC */ +#define IO_NMI IO_RTC /* NMI Control */ +#define IO_DMAPG 0x080 /* DMA Page Registers */ +#define IO_ICU2 0x0A0 /* 8259A Interrupt Controller #2 */ +#define IO_DMA2 0x0C0 /* 8237A DMA Controller #2 */ +#define IO_NPX 0x0F0 /* Numeric Coprocessor */ + + /* Cards */ + /* 0x100 - 0x16F Open */ + +#define IO_WD2 0x170 /* Secondary Fixed Disk Controller */ + + /* 0x178 - 0x1EF Open */ + +#define IO_WD1 0x1f0 /* Primary Fixed Disk Controller */ +#define IO_GAME 0x200 /* Game Controller */ + + /* 0x208 - 0x277 Open */ + +#define IO_LPT2 0x278 /* Parallel Port #2 */ + + /* 0x280 - 0x2E7 Open */ + +#define IO_COM4 0x2e8 /* COM4 i/o address */ + + /* 0x2F0 - 0x2F7 Open */ + +#define IO_COM2 0x2f8 /* COM2 i/o address */ + /* 0x300 - 0x32F Open */ + +#define IO_BT0 0x330 /* bustek 742a default addr. */ +#define IO_AHA0 0x330 /* adaptec 1542 default addr. */ +#define IO_UHA0 0x330 /* ultrastore 14f default addr. */ +#define IO_BT1 0x334 /* bustek 742a default addr. */ +#define IO_AHA1 0x334 /* adaptec 1542 default addr. */ + /* 0x338 - 0x36F Open */ + +#define IO_FD2 0x370 /* secondary base i/o address */ +#define IO_LPT1 0x378 /* Parallel Port #1 */ + + /* 0x380 - 0x3AF Open */ + +#define IO_MDA 0x3B0 /* Monochome Adapter */ +#define IO_LPT3 0x3BC /* Monochome Adapter Printer Port */ +#define IO_VGA 0x3C0 /* E/VGA Ports */ +#define IO_CGA 0x3D0 /* CGA Ports */ + + /* 0x3E0 - 0x3E7 Open */ + +#define IO_COM3 0x3e8 /* COM3 i/o address */ +#define IO_FD1 0x3f0 /* primary base i/o address */ +#define IO_COM1 0x3f8 /* COM1 i/o address */ + +#define IO_ISAEND 0x3FF /* - 0x3FF End of I/O Registers */ +#endif IO_ISABEGIN + +/* + * Input / Output Port Sizes - these are from several sources, and tend + * to be the larger of what was found, ie COM ports can be 4, but some + * boards do not fully decode the address, thus 8 ports are used. + */ + +#ifndef IO_ISASIZES +#define IO_ISASIZES + +#define IO_COMSIZE 8 /* 8250, 16X50 com controllers (4?) */ +#define IO_CGASIZE 16 /* CGA controllers */ +#define IO_DMASIZE 16 /* 8237 DMA controllers */ +#define IO_DPGSIZE 32 /* 74LS612 DMA page reisters */ +#define IO_FDCSIZE 8 /* Nec765 floppy controllers */ +#define IO_WDCSIZE 8 /* WD compatible disk controllers */ +#define IO_GAMSIZE 16 /* AT compatible game controllers */ +#define IO_ICUSIZE 16 /* 8259A interrupt controllers */ +#define IO_KBDSIZE 16 /* 8042 Keyboard controllers */ +#define IO_LPTSIZE 8 /* LPT controllers, some use only 4 */ +#define IO_MDASIZE 16 /* Monochrome display controllers */ +#define IO_RTCSIZE 16 /* CMOS real time clock, NMI control */ +#define IO_TMRSIZE 16 /* 8253 programmable timers */ +#define IO_NPXSIZE 16 /* 80387/80487 NPX registers */ +#define IO_VGASIZE 16 /* VGA controllers */ + +#endif /* IO_ISASIZES */ + +/* + * Input / Output Memory Physical Addresses + */ + +#ifndef IOM_BEGIN +#define IOM_BEGIN 0x0a0000 /* Start of I/O Memory "hole" */ +#define IOM_END 0x100000 /* End of I/O Memory "hole" */ +#define IOM_SIZE (IOM_END - IOM_BEGIN) +#endif IOM_BEGIN + +/* + * RAM Physical Address Space (ignoring the above mentioned "hole") + */ + +#ifndef RAM_BEGIN +#define RAM_BEGIN 0x0000000 /* Start of RAM Memory */ +#define RAM_END 0x1000000 /* End of RAM Memory */ +#define RAM_SIZE (RAM_END - RAM_BEGIN) +#endif RAM_BEGIN + +/* + * Oddball Physical Memory Addresses + */ +#ifndef COMPAQ_RAMRELOC +#define COMPAQ_RAMRELOC 0x80c00000 /* Compaq RAM relocation/diag */ +#define COMPAQ_RAMSETUP 0x80c00002 /* Compaq RAM setup */ +#define WEITEK_FPU 0xC0000000 /* WTL 2167 */ +#define CYRIX_EMC 0xC0000000 /* Cyrix EMC */ +#endif COMPAQ_RAMRELOC diff --git a/sys/amd64/isa/npx.c b/sys/amd64/isa/npx.c new file mode 100644 index 000000000000..73392fabfc5e --- /dev/null +++ b/sys/amd64/isa/npx.c @@ -0,0 +1,564 @@ +/*- + * Copyright (c) 1990 William Jolitz. + * 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. + * + * @(#)npx.c 7.2 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Bruce Evans New npx-0.5 code + * 23 May 93 Rodney W. Grimes Return a special value of -1 from + * the probe code to keep isa_config from + * printing out the I/O address when we + * are using trap 16 handling. + * + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/isa/RCS/npx.c,v 1.2 92/01/21 14:34:27 william Exp $"; + +#include "npx.h" +#if NNPX > 0 + +#include "param.h" +#include "systm.h" +#include "conf.h" +#include "file.h" +#include "proc.h" +#include "machine/cpu.h" +#include "machine/pcb.h" +#include "machine/trap.h" +#include "ioctl.h" +#include "machine/specialreg.h" +#include "i386/isa/icu.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/isa.h" + +/* + * 387 and 287 Numeric Coprocessor Extension (NPX) Driver. + */ + +#ifdef __GNUC__ + +#define disable_intr() __asm("cli") +#define enable_intr() __asm("sti") +#define fldcw(addr) __asm("fldcw %0" : : "m" (*addr)) +#define fnclex() __asm("fnclex") +#define fninit() __asm("fninit") +#define fnsave(addr) __asm("fnsave %0" : "=m" (*addr) : "0" (*addr)) +#define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr)) +#define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr)) +#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fwait") +#define frstor(addr) __asm("frstor %0" : : "m" (*addr)) +#define fwait() __asm("fwait") +#define read_eflags() ({u_long ef; \ + __asm("pushf; popl %0" : "=a" (ef)); \ + ef; }) +#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \ + : : "n" (CR0_TS) : "ax") +#define stop_emulating() __asm("clts") +#define write_eflags(ef) __asm("pushl %0; popf" : : "a" ((u_long) ef)) + +#else /* not __GNUC__ */ + +void disable_intr __P((void)); +void enable_intr __P((void)); +void fldcw __P((caddr_t addr)); +void fnclex __P((void)); +void fninit __P((void)); +void fnsave __P((caddr_t addr)); +void fnstcw __P((caddr_t addr)); +void fnstsw __P((caddr_t addr)); +void fp_divide_by_0 __P((void)); +void frstor __P((caddr_t addr)); +void fwait __P((void)); +u_long read_eflags __P((void)); +void start_emulating __P((void)); +void stop_emulating __P((void)); +void write_eflags __P((u_long ef)); + +#endif /* __GNUC__ */ + +typedef u_char bool_t; + +extern struct gate_descriptor idt[]; + +int npxdna __P((void)); +void npxexit __P((struct proc *p)); +void npxinit __P((u_int control)); +void npxintr __P((struct intrframe frame)); +void npxsave __P((struct save87 *addr)); +static int npxattach __P((struct isa_device *dvp)); +static int npxprobe __P((struct isa_device *dvp)); +static int npxprobe1 __P((struct isa_device *dvp)); + +struct isa_driver npxdriver = { + npxprobe, npxattach, "npx", +}; + +u_int npx0mask; +struct proc *npxproc; + +static bool_t npx_ex16; +static bool_t npx_exists; +static struct gate_descriptor npx_idt_probeintr; +static int npx_intrno; +static volatile u_int npx_intrs_while_probing; +static bool_t npx_irq13; +static volatile u_int npx_traps_while_probing; + +/* + * Special interrupt handlers. Someday intr0-intr15 will be used to count + * interrupts. We'll still need a special exception 16 handler. The busy + * latch stuff in probintr() can be moved to npxprobe(). + */ +void probeintr(void); +asm +(" + .text +_probeintr: + ss + incl _npx_intrs_while_probing + pushl %eax + movb $0x20,%al /* EOI (asm in strings loses cpp features) */ + outb %al,$0xa0 /* IO_ICU2 */ + outb %al,$0x20 /* IO_ICU1 */ + movb $0,%al + outb %al,$0xf0 /* clear BUSY# latch */ + popl %eax + iret +"); + +void probetrap(void); +asm +(" + .text +_probetrap: + ss + incl _npx_traps_while_probing + fnclex + iret +"); + +/* + * Probe routine. Initialize cr0 to give correct behaviour for [f]wait + * whether the device exists or not (XXX should be elsewhere). Set flags + * to tell npxattach() what to do. Modify device struct if npx doesn't + * need to use interrupts. Return 1 if device exists. + */ +static int +npxprobe(dvp) + struct isa_device *dvp; +{ + int result; + u_long save_eflags; + u_char save_icu1_mask; + u_char save_icu2_mask; + struct gate_descriptor save_idt_npxintr; + struct gate_descriptor save_idt_npxtrap; + /* + * This routine is now just a wrapper for npxprobe1(), to install + * special npx interrupt and trap handlers, to enable npx interrupts + * and to disable other interrupts. Someday isa_configure() will + * install suitable handlers and run with interrupts enabled so we + * won't need to do so much here. + */ + npx_intrno = NRSVIDT + ffs(dvp->id_irq) - 1; + save_eflags = read_eflags(); + disable_intr(); + save_icu1_mask = inb(IO_ICU1 + 1); + save_icu2_mask = inb(IO_ICU2 + 1); + save_idt_npxintr = idt[npx_intrno]; + save_idt_npxtrap = idt[16]; + outb(IO_ICU1 + 1, ~(IRQ_SLAVE | dvp->id_irq)); + outb(IO_ICU2 + 1, ~(dvp->id_irq >> 8)); + setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL); + setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL); + npx_idt_probeintr = idt[npx_intrno]; + enable_intr(); + result = npxprobe1(dvp); + disable_intr(); + outb(IO_ICU1 + 1, save_icu1_mask); + outb(IO_ICU2 + 1, save_icu2_mask); + idt[npx_intrno] = save_idt_npxintr; + idt[16] = save_idt_npxtrap; + write_eflags(save_eflags); + return (result); +} + +static int +npxprobe1(dvp) + struct isa_device *dvp; +{ + int control; + int status; +#ifdef lint + npxintr(); +#endif + /* + * Partially reset the coprocessor, if any. Some BIOS's don't reset + * it after a warm boot. + */ + outb(0xf1, 0); /* full reset on some systems, NOP on others */ + outb(0xf0, 0); /* clear BUSY# latch */ + /* + * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT + * instructions. We must set the CR0_MP bit and use the CR0_TS + * bit to control the trap, because setting the CR0_EM bit does + * not cause WAIT instructions to trap. It's important to trap + * WAIT instructions - otherwise the "wait" variants of no-wait + * control instructions would degenerate to the "no-wait" variants + * after FP context switches but work correctly otherwise. It's + * particularly important to trap WAITs when there is no NPX - + * otherwise the "wait" variants would always degenerate. + * + * Try setting CR0_NE to get correct error reporting on 486DX's. + * Setting it should fail or do nothing on lesser processors. + */ + load_cr0(rcr0() | CR0_MP | CR0_NE); + /* + * But don't trap while we're probing. + */ + stop_emulating(); + /* + * Finish resetting the coprocessor, if any. If there is an error + * pending, then we may get a bogus IRQ13, but probeintr() will handle + * it OK. Bogus halts have never been observed, but we enabled + * IRQ13 and cleared the BUSY# latch early to handle them anyway. + */ + fninit(); + DELAY(1000); /* wait for any IRQ13 (fwait might hang) */ +#ifdef DIAGNOSTIC + if (npx_intrs_while_probing != 0) + printf("fninit caused %u bogus npx interrupt(s)\n", + npx_intrs_while_probing); + if (npx_traps_while_probing != 0) + printf("fninit caused %u bogus npx trap(s)\n", + npx_traps_while_probing); +#endif + /* + * Check for a status of mostly zero. + */ + status = 0x5a5a; + fnstsw(&status); + if ((status & 0xb8ff) == 0) { + /* + * Good, now check for a proper control word. + */ + control = 0x5a5a; + fnstcw(&control); + if ((control & 0x1f3f) == 0x033f) { + npx_exists = 1; + /* + * We have an npx, now divide by 0 to see if exception + * 16 works. + */ + control &= ~(1 << 2); /* enable divide by 0 trap */ + fldcw(&control); + npx_traps_while_probing = npx_intrs_while_probing = 0; + fp_divide_by_0(); + if (npx_traps_while_probing != 0) { + /* + * Good, exception 16 works. + */ + npx_ex16 = 1; + dvp->id_irq = 0; /* zap the interrupt */ + /* + * special return value to flag that we do not + * actually use any I/O registers + */ + return (-1); + } + if (npx_intrs_while_probing != 0) { + /* + * Bad, we are stuck with IRQ13. + */ + npx_irq13 = 1; + npx0mask = dvp->id_irq; /* npxattach too late */ + return (IO_NPXSIZE); + } + /* + * Worse, even IRQ13 is broken. Use emulator. + */ + } + } + /* + * Probe failed, but we want to get to npxattach to initialize the + * emulator and say that it has been installed. XXX handle devices + * that aren't really devices better. + */ + dvp->id_irq = 0; + return (IO_NPXSIZE); +} + +/* + * Attach routine - announce which it is, and wire into system + */ +int +npxattach(dvp) + struct isa_device *dvp; +{ + if (npx_ex16) + printf(" <Errors reported via Exception 16>"); + else if (npx_irq13) + printf(" <Errors reported via IRQ 13>"); + else if (npx_exists) + printf(" <Error reporting broken, using 387 emulator>"); + else + printf(" <387 Emulator>"); + npxinit(__INITIAL_NPXCW__); + return (1); /* XXX unused */ +} + +/* + * Initialize floating point unit. + */ +void +npxinit(control) + u_int control; +{ + struct save87 dummy; + + if (!npx_exists) + return; + /* + * fninit has the same h/w bugs as fnsave. Use the detoxified + * fnsave to throw away any junk in the fpu. fnsave initializes + * the fpu and sets npxproc = NULL as important side effects. + */ + npxsave(&dummy); + stop_emulating(); + fldcw(&control); + if (curpcb != NULL) + fnsave(&curpcb->pcb_savefpu); + start_emulating(); +} + +/* + * Free coprocessor (if we have it). + */ +void +npxexit(p) + struct proc *p; +{ + + if (p == npxproc) { + start_emulating(); + npxproc = NULL; + } +} + +/* + * Record the FPU state and reinitialize it all except for the control word. + * Then generate a SIGFPE. + * + * Reinitializing the state allows naive SIGFPE handlers to longjmp without + * doing any fixups. + * + * XXX there is currently no way to pass the full error state to signal + * handlers, and if this is a nested interrupt there is no way to pass even + * a status code! So there is no way to have a non-naive SIGFPE handler. At + * best a handler could do an fninit followed by an fldcw of a static value. + * fnclex would be of little use because it would leave junk on the FPU stack. + * Returning from the handler would be even less safe than usual because + * IRQ13 exception handling makes exceptions even less precise than usual. + */ +void +npxintr(frame) + struct intrframe frame; +{ + int code; + + if (npxproc == NULL || !npx_exists) { + /* XXX no %p in stand/printf.c. Cast to quiet gcc -Wall. */ + printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n", + (u_long) npxproc, (u_long) curproc, npx_exists); + panic("npxintr from nowhere"); + } + if (npxproc != curproc) { + printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n", + (u_long) npxproc, (u_long) curproc, npx_exists); + panic("npxintr from non-current process"); + } + /* + * Save state. This does an implied fninit. It had better not halt + * the cpu or we'll hang. + */ + outb(0xf0, 0); + fnsave(&curpcb->pcb_savefpu); + fwait(); + /* + * Restore control word (was clobbered by fnsave). + */ + fldcw(&curpcb->pcb_savefpu.sv_env.en_cw); + fwait(); + /* + * Remember the exception status word and tag word. The current + * (almost fninit'ed) fpu state is in the fpu and the exception + * state just saved will soon be junk. However, the implied fninit + * doesn't change the error pointers or register contents, and we + * preserved the control word and will copy the status and tag + * words, so the complete exception state can be recovered. + */ + curpcb->pcb_savefpu.sv_ex_sw = curpcb->pcb_savefpu.sv_env.en_sw; + curpcb->pcb_savefpu.sv_ex_tw = curpcb->pcb_savefpu.sv_env.en_tw; + + /* + * Pass exception to process. + */ + if (ISPL(frame.if_cs) == SEL_UPL) { + /* + * Interrupt is essentially a trap, so we can afford to call + * the SIGFPE handler (if any) as soon as the interrupt + * returns. + * + * XXX little or nothing is gained from this, and plenty is + * lost - the interrupt frame has to contain the trap frame + * (this is otherwise only necessary for the rescheduling trap + * in doreti, and the frame for that could easily be set up + * just before it is used). + */ + curproc->p_regs = (int *)&frame.if_es; + curpcb->pcb_flags |= FM_TRAP; /* used by sendsig */ +#ifdef notyet + /* + * Encode the appropriate code for detailed information on + * this exception. + */ + code = XXX_ENCODE(curpcb->pcb_savefpu.sv_ex_sw); +#else + code = 0; /* XXX */ +#endif + trapsignal(curproc, SIGFPE, code); + curpcb->pcb_flags &= ~FM_TRAP; + } else { + /* + * Nested interrupt. These losers occur when: + * o an IRQ13 is bogusly generated at a bogus time, e.g.: + * o immediately after an fnsave or frstor of an + * error state. + * o a couple of 386 instructions after + * "fstpl _memvar" causes a stack overflow. + * These are especially nasty when combined with a + * trace trap. + * o an IRQ13 occurs at the same time as another higher- + * priority interrupt. + * + * Treat them like a true async interrupt. + */ + psignal(npxproc, SIGFPE); + } +} + +/* + * Implement device not available (DNA) exception + * + * It would be better to switch FP context here (only). This would require + * saving the state in the proc table instead of in the pcb. + */ +int +npxdna() +{ + if (!npx_exists) + return (0); + if (npxproc != NULL) { + printf("npxdna: npxproc = %lx, curproc = %lx\n", + (u_long) npxproc, (u_long) curproc); + panic("npxdna"); + } + stop_emulating(); + /* + * Record new context early in case frstor causes an IRQ13. + */ + npxproc = curproc; + /* + * The following frstor may cause an IRQ13 when the state being + * restored has a pending error. The error will appear to have been + * triggered by the current (npx) user instruction even when that + * instruction is a no-wait instruction that should not trigger an + * error (e.g., fnclex). On at least one 486 system all of the + * no-wait instructions are broken the same as frstor, so our + * treatment does not amplify the breakage. On at least one + * 386/Cyrix 387 system, fnclex works correctly while frstor and + * fnsave are broken, so our treatment breaks fnclex if it is the + * first FPU instruction after a context switch. + */ + frstor(&curpcb->pcb_savefpu); + + return (1); +} + +/* + * Wrapper for fnsave instruction to handle h/w bugs. If there is an error + * pending, then fnsave generates a bogus IRQ13 on some systems. Force + * any IRQ13 to be handled immediately, and then ignore it. This routine is + * often called at splhigh so it must not use many system services. In + * particular, it's much easier to install a special handler than to + * guarantee that it's safe to use npxintr() and its supporting code. + */ +void +npxsave(addr) + struct save87 *addr; +{ + u_char icu1_mask; + u_char icu2_mask; + u_char old_icu1_mask; + u_char old_icu2_mask; + struct gate_descriptor save_idt_npxintr; + + disable_intr(); + old_icu1_mask = inb(IO_ICU1 + 1); + old_icu2_mask = inb(IO_ICU2 + 1); + save_idt_npxintr = idt[npx_intrno]; + outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0mask)); + outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0mask >> 8)); + idt[npx_intrno] = npx_idt_probeintr; + enable_intr(); + stop_emulating(); + fnsave(addr); + fwait(); + start_emulating(); + npxproc = NULL; + disable_intr(); + icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */ + icu2_mask = inb(IO_ICU2 + 1); + outb(IO_ICU1 + 1, + (icu1_mask & ~npx0mask) | (old_icu1_mask & npx0mask)); + outb(IO_ICU2 + 1, + (icu2_mask & ~(npx0mask >> 8)) + | (old_icu2_mask & (npx0mask >> 8))); + idt[npx_intrno] = save_idt_npxintr; + enable_intr(); /* back to usual state */ +} + +#endif /* NNPX > 0 */ diff --git a/sys/amd64/isa/timerreg.h b/sys/amd64/isa/timerreg.h new file mode 100644 index 000000000000..72c70227e3ed --- /dev/null +++ b/sys/amd64/isa/timerreg.h @@ -0,0 +1,89 @@ +/*- + * 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. + * + * $Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp $ + * + * 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. + */ + +/* + * 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/amd64/isa/vector.S b/sys/amd64/isa/vector.S new file mode 100644 index 000000000000..38ac79cdb347 --- /dev/null +++ b/sys/amd64/isa/vector.S @@ -0,0 +1,376 @@ +/* vector.s */ +/* + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00167 + * -------------------- ----- ---------------------- + * + * 04 Jun 93 Bruce Evans Fixed irq_num vs id_num for multiple + * devices configed on the same irq with + * respect to ipending. + * + */ + +#include "i386/isa/icu.h" +#include "i386/isa/isa.h" +#include "vector.h" + +#define ICU_EOI 0x20 /* XXX - define elsewhere */ + +#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8)) +#define IRQ_BYTE(irq_num) ((irq_num) / 8) + +#define ENABLE_ICU1 \ + movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ + FASTER_NOP ; /* ... ASAP ... */ \ + outb %al,$IO_ICU1 /* ... to clear in service bit */ +#ifdef AUTO_EOI_1 +#undef ENABLE_ICU1 /* we now use auto-EOI to reduce i/o */ +#define ENABLE_ICU1 +#endif + +#define ENABLE_ICU1_AND_2 \ + movb $ICU_EOI,%al ; /* as above */ \ + FASTER_NOP ; \ + outb %al,$IO_ICU2 ; /* but do second icu first */ \ + FASTER_NOP ; \ + outb %al,$IO_ICU1 /* then first icu */ +#ifdef AUTO_EOI_2 +#undef ENABLE_ICU1_AND_2 /* data sheet says no auto-EOI on slave ... */ +#define ENABLE_ICU1_AND_2 /* ... but it works */ +#endif + +/* + * Macros for interrupt interrupt entry, call to handler, and exit. + * + * XXX - the interrupt frame is set up to look like a trap frame. This is + * usually a waste of time. The only interrupt handlers that want a frame + * are the clock handler (it wants a clock frame), the npx handler (it's + * easier to do right all in assembler). The interrupt return routine + * needs a trap frame for rare AST's (it could easily convert the frame). + * The direct costs of setting up a trap frame are two pushl's (error + * code and trap number), an addl to get rid of these, and pushing and + * popping the call-saved regs %esi, %edi and %ebp twice, The indirect + * costs are making the driver interface nonuniform so unpending of + * interrupts is more complicated and slower (call_driver(unit) would + * be easier than ensuring an interrupt frame for all handlers. Finally, + * there are some struct copies in the npx handler and maybe in the clock + * handler that could be avoided by working more with pointers to frames + * instead of frames. + * + * XXX - should we do a cld on every system entry to avoid the requirement + * for scattered cld's? + * + * Coding notes for *.s: + * + * If possible, avoid operations that involve an operand size override. + * Word-sized operations might be smaller, but the operand size override + * makes them slower on on 486's and no faster on 386's unless perhaps + * the instruction pipeline is depleted. E.g., + * + * Use movl to seg regs instead of the equivalent but more descriptive + * movw - gas generates an irelevant (slower) operand size override. + * + * Use movl to ordinary regs in preference to movw and especially + * in preference to movz[bw]l. Use unsigned (long) variables with the + * top bits clear instead of unsigned short variables to provide more + * opportunities for movl. + * + * If possible, use byte-sized operations. They are smaller and no slower. + * + * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter. + * + * If the interrupt frame is made more flexible, INTR can push %eax first + * and decide the ipending case with less overhead, e.g., by avoiding + * loading segregs. + */ + +#define FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \ + pushl %eax ; /* save only call-used registers */ \ + pushl %ecx ; \ + pushl %edx ; \ + pushl %ds ; \ + /* pushl %es ; know compiler doesn't do string insns */ \ + movl $KDSEL,%eax ; \ + movl %ax,%ds ; \ + /* movl %ax,%es ; */ \ + SHOW_CLI ; /* although it interferes with "ASAP" */ \ + pushl $unit ; \ + call handler ; /* do the work ASAP */ \ + enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \ + addl $4,%esp ; \ + incl _cnt+V_INTR ; /* book-keeping can wait */ \ + COUNT_EVENT(_intrcnt_actv, id_num) ; \ + SHOW_STI ; \ + /* popl %es ; */ \ + popl %ds ; \ + popl %edx; \ + popl %ecx; \ + popl %eax; \ + iret + +#define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \ + pushl $0 ; /* dummy error code */ \ + pushl $T_ASTFLT ; \ + pushal ; \ + pushl %ds ; /* save our data and extra segments ... */ \ + pushl %es ; \ + movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \ + movl %ax,%ds ; /* ... early in case SHOW_A_LOT is on */ \ + movl %ax,%es ; \ + SHOW_CLI ; /* interrupt did an implicit cli */ \ + movb _imen + IRQ_BYTE(irq_num),%al ; \ + orb $IRQ_BIT(irq_num),%al ; \ + movb %al,_imen + IRQ_BYTE(irq_num) ; \ + SHOW_IMEN ; \ + FASTER_NOP ; \ + outb %al,$icu+1 ; \ + enable_icus ; \ + incl _cnt+V_INTR ; /* tally interrupts */ \ + movl _cpl,%eax ; \ + testb $IRQ_BIT(irq_num),%reg ; \ + jne 2f ; \ +1: ; \ + COUNT_EVENT(_intrcnt_actv, id_num) ; \ + movl _cpl,%eax ; \ + pushl %eax ; \ + pushl $unit ; \ + orl mask,%eax ; \ + movl %eax,_cpl ; \ + SHOW_CPL ; \ + SHOW_STI ; \ + sti ; \ + call handler ; \ + movb _imen + IRQ_BYTE(irq_num),%al ; \ + andb $~IRQ_BIT(irq_num),%al ; \ + movb %al,_imen + IRQ_BYTE(irq_num) ; \ + SHOW_IMEN ; \ + FASTER_NOP ; \ + outb %al,$icu+1 ; \ + jmp doreti ; \ +; \ + ALIGN_TEXT ; \ +2: ; \ + COUNT_EVENT(_intrcnt_pend, id_num) ; \ + movl $1b,%eax ; /* register resume address */ \ + /* XXX - someday do it at attach time */ \ + movl %eax,Vresume + (irq_num) * 4 ; \ + orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \ + SHOW_IPENDING ; \ + popl %es ; \ + popl %ds ; \ + popal ; \ + addl $4+4,%esp ; \ + iret + +/* + * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info + * about vectors, including a submacro 'BUILD_VECTOR' that operates on the + * info about each vector. We redefine 'BUILD_VECTOR' to expand the info + * in different ways. Here we expand it to a list of interrupt handlers. + * This order is of course unimportant. Elsewhere we expand it to inline + * linear search code for which the order is a little more important and + * concatenating the code with no holes is very important. + * + * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR. + * + * The info consists of the following items for each vector: + * + * name (identifier): name of the vector; used to build labels + * unit (expression): unit number to call the device driver with + * irq_num (number): number of the IRQ to handled (0-15) + * id_num (number): uniq numeric id for handler (assigned by config) + * mask (blank-ident): priority mask used + * handler (blank-ident): interrupt handler to call + * icu_num (number): (1 + irq_num / 8) converted for label building + * icu_enables (number): 1 for icu_num == 1, 1_AND_2 for icu_num == 2 + * reg (blank-ident): al for icu_num == 1, ah for icu_num == 2 + * + * 'irq_num' is converted in several ways at config time to get around + * limitations in cpp. The macros have blanks after commas iff they would + * not mess up identifiers and numbers. + */ + +#undef BUILD_FAST_VECTOR +#define BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \ + icu_num, icu_enables, reg) \ + .globl handler ; \ + .text ; \ + .globl _V/**/name ; \ + SUPERALIGN_TEXT ; \ +_V/**/name: ; \ + FAST_INTR(unit, irq_num, id_num, handler, ENABLE_ICU/**/icu_enables) + +#undef BUILD_VECTOR +#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ + icu_num, icu_enables, reg) \ + .globl handler ; \ + .text ; \ + .globl _V/**/name ; \ + SUPERALIGN_TEXT ; \ +_V/**/name: ; \ + INTR(unit,irq_num,id_num, mask, handler, IO_ICU/**/icu_num, \ + ENABLE_ICU/**/icu_enables, reg,) + + BUILD_VECTORS + + /* hardware interrupt catcher (IDT 32 - 47) */ + .globl _isa_strayintr + +#define STRAYINTR(irq_num, icu_num, icu_enables, reg) \ +IDTVEC(intr/**/irq_num) ; \ + INTR(irq_num,irq_num,irq_num, _highmask, _isa_strayintr, \ + IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray) + +/* + * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead + * of the mask IRQ2 (defined as IRQ9 == (1 << 9)). But IRQ 2 "can't happen". + * In fact, all stray interrupts "can't happen" except for bugs. The + * "stray" IRQ 7 is documented behaviour of the 8259. It happens when there + * is a glitch on any of its interrupt inputs. Does it really interrupt when + * IRQ 7 is masked? + * + * XXX - unpend doesn't work for these, it sends them to the real handler. + * + * XXX - the race bug during initialization may be because I changed the + * order of switching from the stray to the real interrupt handler to before + * enabling interrupts. The old order looked unsafe but maybe it is OK with + * the stray interrupt handler installed. But these handlers only reduce + * the window of vulnerability - it is still open at the end of + * isa_configure(). + * + * XXX - many comments are stale. + */ + + STRAYINTR(0,1,1, al) + STRAYINTR(1,1,1, al) + STRAYINTR(2,1,1, al) + STRAYINTR(3,1,1, al) + STRAYINTR(4,1,1, al) + STRAYINTR(5,1,1, al) + STRAYINTR(6,1,1, al) + STRAYINTR(8,2,1_AND_2, ah) + STRAYINTR(9,2,1_AND_2, ah) + STRAYINTR(10,2,1_AND_2, ah) + STRAYINTR(11,2,1_AND_2, ah) + STRAYINTR(12,2,1_AND_2, ah) + STRAYINTR(13,2,1_AND_2, ah) + STRAYINTR(14,2,1_AND_2, ah) + STRAYINTR(15,2,1_AND_2, ah) +IDTVEC(intrdefault) + STRAYINTR(7,1,1, al) /* XXX */ +#if 0 + INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2 +#endif +/* + * These are the interrupt counters, I moved them here from icu.s so that + * they are with the name table. rgrimes + * + * There are now lots of counters, this has been redone to work with + * Bruce Evans intr-0.1 code, which I modified some more to make it all + * work with vmstat. + */ + .data +Vresume: .space 16 * 4 /* where to resume intr handler after unpend */ + .globl _intrcnt +_intrcnt: /* used by vmstat to calc size of table */ + .globl _intrcnt_bad7 +_intrcnt_bad7: .space 4 /* glitches on irq 7 */ + .globl _intrcnt_bad15 +_intrcnt_bad15: .space 4 /* glitches on irq 15 */ + .globl _intrcnt_stray +_intrcnt_stray: .space 4 /* total count of stray interrupts */ + .globl _intrcnt_actv +_intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */ + .globl _intrcnt_pend +_intrcnt_pend: .space NR_REAL_INT_HANDLERS * 4 /* pending interrupts */ + .globl _intrcnt_spl +_intrcnt_spl: .space 32 * 4 /* XXX 32 should not be hard coded ? */ + .globl _intrcnt_show +_intrcnt_show: .space 8 * 4 /* XXX 16 should not be hard coded ? */ + .globl _eintrcnt +_eintrcnt: /* used by vmstat to calc size of table */ + +/* + * Build the interrupt name table for vmstat + */ + +#undef BUILD_FAST_VECTOR +#define BUILD_FAST_VECTOR BUILD_VECTOR + +#undef BUILD_VECTOR +#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ + icu_num, icu_enables, reg) \ + .ascii "name irq" ; \ + .asciz "irq_num" +/* + * XXX - use the STRING and CONCAT macros from <sys/cdefs.h> to stringize + * and concatenate names above and elsewhere. + */ + + .text + .globl _intrnames, _eintrnames +_intrnames: + BUILD_VECTOR(bad,,7,,,,,,) + BUILD_VECTOR(bad,,15,,,,,,) + BUILD_VECTOR(stray,,,,,,,,) + BUILD_VECTORS + +#undef BUILD_FAST_VECTOR +#define BUILD_FAST_VECTOR BUILD_VECTOR + +#undef BUILD_VECTOR +#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ + icu_num, icu_enables, reg) \ + .asciz "name pend" + + BUILD_VECTORS + +/* + * now the spl names + */ + .asciz "unpend_v" + .asciz "doreti" + .asciz "p0!ni" + .asciz "!p0!ni" + .asciz "p0ni" + .asciz "netisr_raw" + .asciz "netisr_ip" + .asciz "netisr_imp" + .asciz "netisr_ns" + .asciz "softclock" + .asciz "trap" + .asciz "doreti_exit2" + .asciz "splbio" + .asciz "splclock" + .asciz "splhigh" + .asciz "splimp" + .asciz "splnet" + .asciz "splsoftclock" + .asciz "spltty" + .asciz "spl0" + .asciz "netisr_raw2" + .asciz "netisr_ip2" + .asciz "splx" + .asciz "splx!0" + .asciz "unpend_V" + .asciz "spl25" /* spl25-spl31 are spares */ + .asciz "spl26" + .asciz "spl27" + .asciz "spl28" + .asciz "spl29" + .asciz "spl30" + .asciz "spl31" +/* + * now the mask names + */ + .asciz "cli" + .asciz "cpl" + .asciz "imen" + .asciz "ipending" + .asciz "sti" + .asciz "mask5" /* mask5-mask7 are spares */ + .asciz "mask6" + .asciz "mask7" + +_eintrnames: diff --git a/sys/amd64/isa/vector.s b/sys/amd64/isa/vector.s new file mode 100644 index 000000000000..38ac79cdb347 --- /dev/null +++ b/sys/amd64/isa/vector.s @@ -0,0 +1,376 @@ +/* vector.s */ +/* + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00167 + * -------------------- ----- ---------------------- + * + * 04 Jun 93 Bruce Evans Fixed irq_num vs id_num for multiple + * devices configed on the same irq with + * respect to ipending. + * + */ + +#include "i386/isa/icu.h" +#include "i386/isa/isa.h" +#include "vector.h" + +#define ICU_EOI 0x20 /* XXX - define elsewhere */ + +#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8)) +#define IRQ_BYTE(irq_num) ((irq_num) / 8) + +#define ENABLE_ICU1 \ + movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ + FASTER_NOP ; /* ... ASAP ... */ \ + outb %al,$IO_ICU1 /* ... to clear in service bit */ +#ifdef AUTO_EOI_1 +#undef ENABLE_ICU1 /* we now use auto-EOI to reduce i/o */ +#define ENABLE_ICU1 +#endif + +#define ENABLE_ICU1_AND_2 \ + movb $ICU_EOI,%al ; /* as above */ \ + FASTER_NOP ; \ + outb %al,$IO_ICU2 ; /* but do second icu first */ \ + FASTER_NOP ; \ + outb %al,$IO_ICU1 /* then first icu */ +#ifdef AUTO_EOI_2 +#undef ENABLE_ICU1_AND_2 /* data sheet says no auto-EOI on slave ... */ +#define ENABLE_ICU1_AND_2 /* ... but it works */ +#endif + +/* + * Macros for interrupt interrupt entry, call to handler, and exit. + * + * XXX - the interrupt frame is set up to look like a trap frame. This is + * usually a waste of time. The only interrupt handlers that want a frame + * are the clock handler (it wants a clock frame), the npx handler (it's + * easier to do right all in assembler). The interrupt return routine + * needs a trap frame for rare AST's (it could easily convert the frame). + * The direct costs of setting up a trap frame are two pushl's (error + * code and trap number), an addl to get rid of these, and pushing and + * popping the call-saved regs %esi, %edi and %ebp twice, The indirect + * costs are making the driver interface nonuniform so unpending of + * interrupts is more complicated and slower (call_driver(unit) would + * be easier than ensuring an interrupt frame for all handlers. Finally, + * there are some struct copies in the npx handler and maybe in the clock + * handler that could be avoided by working more with pointers to frames + * instead of frames. + * + * XXX - should we do a cld on every system entry to avoid the requirement + * for scattered cld's? + * + * Coding notes for *.s: + * + * If possible, avoid operations that involve an operand size override. + * Word-sized operations might be smaller, but the operand size override + * makes them slower on on 486's and no faster on 386's unless perhaps + * the instruction pipeline is depleted. E.g., + * + * Use movl to seg regs instead of the equivalent but more descriptive + * movw - gas generates an irelevant (slower) operand size override. + * + * Use movl to ordinary regs in preference to movw and especially + * in preference to movz[bw]l. Use unsigned (long) variables with the + * top bits clear instead of unsigned short variables to provide more + * opportunities for movl. + * + * If possible, use byte-sized operations. They are smaller and no slower. + * + * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter. + * + * If the interrupt frame is made more flexible, INTR can push %eax first + * and decide the ipending case with less overhead, e.g., by avoiding + * loading segregs. + */ + +#define FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \ + pushl %eax ; /* save only call-used registers */ \ + pushl %ecx ; \ + pushl %edx ; \ + pushl %ds ; \ + /* pushl %es ; know compiler doesn't do string insns */ \ + movl $KDSEL,%eax ; \ + movl %ax,%ds ; \ + /* movl %ax,%es ; */ \ + SHOW_CLI ; /* although it interferes with "ASAP" */ \ + pushl $unit ; \ + call handler ; /* do the work ASAP */ \ + enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \ + addl $4,%esp ; \ + incl _cnt+V_INTR ; /* book-keeping can wait */ \ + COUNT_EVENT(_intrcnt_actv, id_num) ; \ + SHOW_STI ; \ + /* popl %es ; */ \ + popl %ds ; \ + popl %edx; \ + popl %ecx; \ + popl %eax; \ + iret + +#define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \ + pushl $0 ; /* dummy error code */ \ + pushl $T_ASTFLT ; \ + pushal ; \ + pushl %ds ; /* save our data and extra segments ... */ \ + pushl %es ; \ + movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \ + movl %ax,%ds ; /* ... early in case SHOW_A_LOT is on */ \ + movl %ax,%es ; \ + SHOW_CLI ; /* interrupt did an implicit cli */ \ + movb _imen + IRQ_BYTE(irq_num),%al ; \ + orb $IRQ_BIT(irq_num),%al ; \ + movb %al,_imen + IRQ_BYTE(irq_num) ; \ + SHOW_IMEN ; \ + FASTER_NOP ; \ + outb %al,$icu+1 ; \ + enable_icus ; \ + incl _cnt+V_INTR ; /* tally interrupts */ \ + movl _cpl,%eax ; \ + testb $IRQ_BIT(irq_num),%reg ; \ + jne 2f ; \ +1: ; \ + COUNT_EVENT(_intrcnt_actv, id_num) ; \ + movl _cpl,%eax ; \ + pushl %eax ; \ + pushl $unit ; \ + orl mask,%eax ; \ + movl %eax,_cpl ; \ + SHOW_CPL ; \ + SHOW_STI ; \ + sti ; \ + call handler ; \ + movb _imen + IRQ_BYTE(irq_num),%al ; \ + andb $~IRQ_BIT(irq_num),%al ; \ + movb %al,_imen + IRQ_BYTE(irq_num) ; \ + SHOW_IMEN ; \ + FASTER_NOP ; \ + outb %al,$icu+1 ; \ + jmp doreti ; \ +; \ + ALIGN_TEXT ; \ +2: ; \ + COUNT_EVENT(_intrcnt_pend, id_num) ; \ + movl $1b,%eax ; /* register resume address */ \ + /* XXX - someday do it at attach time */ \ + movl %eax,Vresume + (irq_num) * 4 ; \ + orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \ + SHOW_IPENDING ; \ + popl %es ; \ + popl %ds ; \ + popal ; \ + addl $4+4,%esp ; \ + iret + +/* + * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info + * about vectors, including a submacro 'BUILD_VECTOR' that operates on the + * info about each vector. We redefine 'BUILD_VECTOR' to expand the info + * in different ways. Here we expand it to a list of interrupt handlers. + * This order is of course unimportant. Elsewhere we expand it to inline + * linear search code for which the order is a little more important and + * concatenating the code with no holes is very important. + * + * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR. + * + * The info consists of the following items for each vector: + * + * name (identifier): name of the vector; used to build labels + * unit (expression): unit number to call the device driver with + * irq_num (number): number of the IRQ to handled (0-15) + * id_num (number): uniq numeric id for handler (assigned by config) + * mask (blank-ident): priority mask used + * handler (blank-ident): interrupt handler to call + * icu_num (number): (1 + irq_num / 8) converted for label building + * icu_enables (number): 1 for icu_num == 1, 1_AND_2 for icu_num == 2 + * reg (blank-ident): al for icu_num == 1, ah for icu_num == 2 + * + * 'irq_num' is converted in several ways at config time to get around + * limitations in cpp. The macros have blanks after commas iff they would + * not mess up identifiers and numbers. + */ + +#undef BUILD_FAST_VECTOR +#define BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \ + icu_num, icu_enables, reg) \ + .globl handler ; \ + .text ; \ + .globl _V/**/name ; \ + SUPERALIGN_TEXT ; \ +_V/**/name: ; \ + FAST_INTR(unit, irq_num, id_num, handler, ENABLE_ICU/**/icu_enables) + +#undef BUILD_VECTOR +#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ + icu_num, icu_enables, reg) \ + .globl handler ; \ + .text ; \ + .globl _V/**/name ; \ + SUPERALIGN_TEXT ; \ +_V/**/name: ; \ + INTR(unit,irq_num,id_num, mask, handler, IO_ICU/**/icu_num, \ + ENABLE_ICU/**/icu_enables, reg,) + + BUILD_VECTORS + + /* hardware interrupt catcher (IDT 32 - 47) */ + .globl _isa_strayintr + +#define STRAYINTR(irq_num, icu_num, icu_enables, reg) \ +IDTVEC(intr/**/irq_num) ; \ + INTR(irq_num,irq_num,irq_num, _highmask, _isa_strayintr, \ + IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray) + +/* + * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead + * of the mask IRQ2 (defined as IRQ9 == (1 << 9)). But IRQ 2 "can't happen". + * In fact, all stray interrupts "can't happen" except for bugs. The + * "stray" IRQ 7 is documented behaviour of the 8259. It happens when there + * is a glitch on any of its interrupt inputs. Does it really interrupt when + * IRQ 7 is masked? + * + * XXX - unpend doesn't work for these, it sends them to the real handler. + * + * XXX - the race bug during initialization may be because I changed the + * order of switching from the stray to the real interrupt handler to before + * enabling interrupts. The old order looked unsafe but maybe it is OK with + * the stray interrupt handler installed. But these handlers only reduce + * the window of vulnerability - it is still open at the end of + * isa_configure(). + * + * XXX - many comments are stale. + */ + + STRAYINTR(0,1,1, al) + STRAYINTR(1,1,1, al) + STRAYINTR(2,1,1, al) + STRAYINTR(3,1,1, al) + STRAYINTR(4,1,1, al) + STRAYINTR(5,1,1, al) + STRAYINTR(6,1,1, al) + STRAYINTR(8,2,1_AND_2, ah) + STRAYINTR(9,2,1_AND_2, ah) + STRAYINTR(10,2,1_AND_2, ah) + STRAYINTR(11,2,1_AND_2, ah) + STRAYINTR(12,2,1_AND_2, ah) + STRAYINTR(13,2,1_AND_2, ah) + STRAYINTR(14,2,1_AND_2, ah) + STRAYINTR(15,2,1_AND_2, ah) +IDTVEC(intrdefault) + STRAYINTR(7,1,1, al) /* XXX */ +#if 0 + INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2 +#endif +/* + * These are the interrupt counters, I moved them here from icu.s so that + * they are with the name table. rgrimes + * + * There are now lots of counters, this has been redone to work with + * Bruce Evans intr-0.1 code, which I modified some more to make it all + * work with vmstat. + */ + .data +Vresume: .space 16 * 4 /* where to resume intr handler after unpend */ + .globl _intrcnt +_intrcnt: /* used by vmstat to calc size of table */ + .globl _intrcnt_bad7 +_intrcnt_bad7: .space 4 /* glitches on irq 7 */ + .globl _intrcnt_bad15 +_intrcnt_bad15: .space 4 /* glitches on irq 15 */ + .globl _intrcnt_stray +_intrcnt_stray: .space 4 /* total count of stray interrupts */ + .globl _intrcnt_actv +_intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */ + .globl _intrcnt_pend +_intrcnt_pend: .space NR_REAL_INT_HANDLERS * 4 /* pending interrupts */ + .globl _intrcnt_spl +_intrcnt_spl: .space 32 * 4 /* XXX 32 should not be hard coded ? */ + .globl _intrcnt_show +_intrcnt_show: .space 8 * 4 /* XXX 16 should not be hard coded ? */ + .globl _eintrcnt +_eintrcnt: /* used by vmstat to calc size of table */ + +/* + * Build the interrupt name table for vmstat + */ + +#undef BUILD_FAST_VECTOR +#define BUILD_FAST_VECTOR BUILD_VECTOR + +#undef BUILD_VECTOR +#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ + icu_num, icu_enables, reg) \ + .ascii "name irq" ; \ + .asciz "irq_num" +/* + * XXX - use the STRING and CONCAT macros from <sys/cdefs.h> to stringize + * and concatenate names above and elsewhere. + */ + + .text + .globl _intrnames, _eintrnames +_intrnames: + BUILD_VECTOR(bad,,7,,,,,,) + BUILD_VECTOR(bad,,15,,,,,,) + BUILD_VECTOR(stray,,,,,,,,) + BUILD_VECTORS + +#undef BUILD_FAST_VECTOR +#define BUILD_FAST_VECTOR BUILD_VECTOR + +#undef BUILD_VECTOR +#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ + icu_num, icu_enables, reg) \ + .asciz "name pend" + + BUILD_VECTORS + +/* + * now the spl names + */ + .asciz "unpend_v" + .asciz "doreti" + .asciz "p0!ni" + .asciz "!p0!ni" + .asciz "p0ni" + .asciz "netisr_raw" + .asciz "netisr_ip" + .asciz "netisr_imp" + .asciz "netisr_ns" + .asciz "softclock" + .asciz "trap" + .asciz "doreti_exit2" + .asciz "splbio" + .asciz "splclock" + .asciz "splhigh" + .asciz "splimp" + .asciz "splnet" + .asciz "splsoftclock" + .asciz "spltty" + .asciz "spl0" + .asciz "netisr_raw2" + .asciz "netisr_ip2" + .asciz "splx" + .asciz "splx!0" + .asciz "unpend_V" + .asciz "spl25" /* spl25-spl31 are spares */ + .asciz "spl26" + .asciz "spl27" + .asciz "spl28" + .asciz "spl29" + .asciz "spl30" + .asciz "spl31" +/* + * now the mask names + */ + .asciz "cli" + .asciz "cpl" + .asciz "imen" + .asciz "ipending" + .asciz "sti" + .asciz "mask5" /* mask5-mask7 are spares */ + .asciz "mask6" + .asciz "mask7" + +_eintrnames: diff --git a/sys/conf/Makefile.i386 b/sys/conf/Makefile.i386 new file mode 100644 index 000000000000..7eedfb83b988 --- /dev/null +++ b/sys/conf/Makefile.i386 @@ -0,0 +1,164 @@ +# Copyright 1990 W. Jolitz +# @(#)Makefile.i386 7.1 5/10/91 +# Makefile for 4.3 BSD-Reno +# +# This makefile is constructed from a machine description: +# config machineid +# Most changes should be made in the machine description +# /sys/i386/conf/``machineid'' +# after which you should do +# config machineid +# Generic makefile changes should be made in +# /sys/i386/conf/Makefile.i386 +# after which config should be rerun for all machines. +# +# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE INVISIBLE 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 +# +# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE +# -------------------- ----- ---------------------- +# CURRENT PATCH LEVEL: 3 00158 +# -------------------- ----- ---------------------- +# +# 29 Jun 92 Chris G. Demetriou Fix vers.o for kernel profiling and +# plain old link +# 25 Mar 93 Sean Eric Fagan Add support for assembler source +# 25 Apr 93 Bruce Evans Support for intr-0.0, and some fixes +# Rodney W. Grimes Added depedencies for conf.o due to +# all the new drivers. And to param.c +# because there were missing. +# 26 May 97 Rodney W. Grimes Remove extra SYSTEM_LD_TAIL +# Redirect stderr from dbsym to null, +# this is bad, but atleast I won't get +# 100's of bug reports about the silly +# warning from dbsym. +# +TOUCH= touch -f -c +LD= /usr/bin/ld +CC= cc +CPP= cpp + +S= ../.. +I386= ../../i386 + +INCLUDES= -I. -I$S -I$S/sys +COPTS= ${INCLUDES} ${IDENT} -DKERNEL -Di386 -DNPX +ASFLAGS= +CFLAGS= -O ${COPTS} + +NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} $< +NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $< +NORMAL_S= ${CPP} -I. -DLOCORE ${COPTS} $< | ${AS} ${ASFLAGS} -o $*.o +DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $< +DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $< +SYSTEM_OBJS=locore.o ${OBJS} param.o ioconf.o conf.o +SYSTEM_DEP=Makefile symbols.sort ${SYSTEM_OBJS} +SYSTEM_LD_HEAD= @echo loading $@; rm -f $@ +SYSTEM_LD= @${LD} -z -T FE000000 -o $@ -X vers.o ${SYSTEM_OBJS} +SYSTEM_LD_TAIL= @echo rearranging symbols; symorder symbols.sort $@; \ + dbsym $@ 2>/dev/null || true; size $@; chmod 755 $@ + +GPROF.EX= /usr/src/lib/csu.i386/gprof.ex +PROFILE_C= ${CC} -S -c ${CFLAGS} $< ; \ + ex - $*.s < ${GPROF.EX} ; \ + ${AS} -o $@ $*.s ; \ + rm -f $*.s + +%OBJS + +%CFILES + +%LOAD + +clean: + rm -f eddep *386bsd tags *.o locore.i [a-uw-z]*.s \ + errs linterrs makelinks genassym + +lint: /tmp param.c + @lint -hbxn -I. -DGENERIC -Dvolatile= ${COPTS} ${PARAM} \ + ${I386}/i386/Locore.c ${CFILES} ioconf.c param.c | \ + grep -v 'struct/union .* never defined' | \ + grep -v 'possible pointer alignment problem' + +symbols.sort: ${I386}/i386/symbols.raw + grep -v '^#' ${I386}/i386/symbols.raw \ + | sed 's/^ //' | sort -u > symbols.sort + +locore.o: assym.s ${I386}/i386/locore.s machine/trap.h machine/psl.h \ + machine/pte.h ${I386}/isa/vector.s ${I386}/isa/icu.s \ + $S/sys/errno.h machine/specialreg.h ${I386}/isa/debug.h \ + ${I386}/isa/icu.h ${I386}/isa/isa.h vector.h $S/net/netisr.h + ${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/locore.s | \ + ${AS} ${ASFLAGS} -o locore.o + +# the following is necessary because autoconf.o depends on #if GENERIC +autoconf.o: Makefile + +# depend on network configuration +af.o uipc_proto.o locore.o: Makefile + +# depend on maxusers +assym.s machdep.o: Makefile + +# depends on KDB (cons.o also depends on GENERIC) +trap.o cons.o: Makefile + +assym.s: $S/sys/param.h machine/pte.h $S/sys/buf.h \ + $S/sys/vmmeter.h \ + $S/sys/proc.h $S/sys/msgbuf.h machine/vmparam.h + +assym.s: genassym + ./genassym >assym.s + +genassym: + ${CC} ${INCLUDES} -DKERNEL ${IDENT} ${PARAM} \ + ${I386}/i386/genassym.c -o genassym + +depend: assym.s param.c + sh /usr/bin/mkdep ${COPTS} ${CFILES} ioconf.c + sh /usr/bin/mkdep -a -p ${INCLUDES} ${IDENT} ${PARAM} ${I386}/i386/genassym.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 $S/sys/param.h machine/pte.h $S/sys/buf.h \ + ${I386}/isa/isa_device.h ${I386}/isa/isa.h ${I386}/isa/icu.h + ${CC} -c ${CFLAGS} ioconf.c + +conf.o: $S/sys/param.h $S/sys/systm.h $S/sys/buf.h $S/sys/ioctl.h \ + $S/sys/tty.h $S/sys/conf.h \ + as.h bpfilter.h cd.h ch.h com.h dcfclk.h fd.h lpa.h \ + lpt.h pty.h sd.h speaker.h st.h wd.h wt.h \ + ${I386}/i386/conf.c + ${CC} -traditional -c ${CFLAGS} ${I386}/i386/conf.c + +param.c: $S/conf/param.c \ + $S/sys/param.h $S/sys/systm.h $S/sys/socket.h $S/sys/proc.h \ + $S/sys/vnode.h $S/sys/file.h $S/sys/callout.h $S/sys/clist.h \ + $S/sys/mbuf.h $S/ufs/quota.h $S/sys/kernel.h machine/vmparam.h \ + $S/sys/shm.h + -rm -f param.c + cp $S/conf/param.c . + +param.o: param.c Makefile + ${CC} -c ${CFLAGS} ${PARAM} param.c + +newvers: + sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT} + ${CC} ${CFLAGS} -c vers.c + +%RULES + +# DO NOT DELETE THIS LINE -- make depend uses it + diff --git a/sys/conf/Makefile.powerpc b/sys/conf/Makefile.powerpc new file mode 100644 index 000000000000..7eedfb83b988 --- /dev/null +++ b/sys/conf/Makefile.powerpc @@ -0,0 +1,164 @@ +# Copyright 1990 W. Jolitz +# @(#)Makefile.i386 7.1 5/10/91 +# Makefile for 4.3 BSD-Reno +# +# This makefile is constructed from a machine description: +# config machineid +# Most changes should be made in the machine description +# /sys/i386/conf/``machineid'' +# after which you should do +# config machineid +# Generic makefile changes should be made in +# /sys/i386/conf/Makefile.i386 +# after which config should be rerun for all machines. +# +# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE INVISIBLE 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 +# +# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE +# -------------------- ----- ---------------------- +# CURRENT PATCH LEVEL: 3 00158 +# -------------------- ----- ---------------------- +# +# 29 Jun 92 Chris G. Demetriou Fix vers.o for kernel profiling and +# plain old link +# 25 Mar 93 Sean Eric Fagan Add support for assembler source +# 25 Apr 93 Bruce Evans Support for intr-0.0, and some fixes +# Rodney W. Grimes Added depedencies for conf.o due to +# all the new drivers. And to param.c +# because there were missing. +# 26 May 97 Rodney W. Grimes Remove extra SYSTEM_LD_TAIL +# Redirect stderr from dbsym to null, +# this is bad, but atleast I won't get +# 100's of bug reports about the silly +# warning from dbsym. +# +TOUCH= touch -f -c +LD= /usr/bin/ld +CC= cc +CPP= cpp + +S= ../.. +I386= ../../i386 + +INCLUDES= -I. -I$S -I$S/sys +COPTS= ${INCLUDES} ${IDENT} -DKERNEL -Di386 -DNPX +ASFLAGS= +CFLAGS= -O ${COPTS} + +NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} $< +NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $< +NORMAL_S= ${CPP} -I. -DLOCORE ${COPTS} $< | ${AS} ${ASFLAGS} -o $*.o +DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $< +DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $< +SYSTEM_OBJS=locore.o ${OBJS} param.o ioconf.o conf.o +SYSTEM_DEP=Makefile symbols.sort ${SYSTEM_OBJS} +SYSTEM_LD_HEAD= @echo loading $@; rm -f $@ +SYSTEM_LD= @${LD} -z -T FE000000 -o $@ -X vers.o ${SYSTEM_OBJS} +SYSTEM_LD_TAIL= @echo rearranging symbols; symorder symbols.sort $@; \ + dbsym $@ 2>/dev/null || true; size $@; chmod 755 $@ + +GPROF.EX= /usr/src/lib/csu.i386/gprof.ex +PROFILE_C= ${CC} -S -c ${CFLAGS} $< ; \ + ex - $*.s < ${GPROF.EX} ; \ + ${AS} -o $@ $*.s ; \ + rm -f $*.s + +%OBJS + +%CFILES + +%LOAD + +clean: + rm -f eddep *386bsd tags *.o locore.i [a-uw-z]*.s \ + errs linterrs makelinks genassym + +lint: /tmp param.c + @lint -hbxn -I. -DGENERIC -Dvolatile= ${COPTS} ${PARAM} \ + ${I386}/i386/Locore.c ${CFILES} ioconf.c param.c | \ + grep -v 'struct/union .* never defined' | \ + grep -v 'possible pointer alignment problem' + +symbols.sort: ${I386}/i386/symbols.raw + grep -v '^#' ${I386}/i386/symbols.raw \ + | sed 's/^ //' | sort -u > symbols.sort + +locore.o: assym.s ${I386}/i386/locore.s machine/trap.h machine/psl.h \ + machine/pte.h ${I386}/isa/vector.s ${I386}/isa/icu.s \ + $S/sys/errno.h machine/specialreg.h ${I386}/isa/debug.h \ + ${I386}/isa/icu.h ${I386}/isa/isa.h vector.h $S/net/netisr.h + ${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/locore.s | \ + ${AS} ${ASFLAGS} -o locore.o + +# the following is necessary because autoconf.o depends on #if GENERIC +autoconf.o: Makefile + +# depend on network configuration +af.o uipc_proto.o locore.o: Makefile + +# depend on maxusers +assym.s machdep.o: Makefile + +# depends on KDB (cons.o also depends on GENERIC) +trap.o cons.o: Makefile + +assym.s: $S/sys/param.h machine/pte.h $S/sys/buf.h \ + $S/sys/vmmeter.h \ + $S/sys/proc.h $S/sys/msgbuf.h machine/vmparam.h + +assym.s: genassym + ./genassym >assym.s + +genassym: + ${CC} ${INCLUDES} -DKERNEL ${IDENT} ${PARAM} \ + ${I386}/i386/genassym.c -o genassym + +depend: assym.s param.c + sh /usr/bin/mkdep ${COPTS} ${CFILES} ioconf.c + sh /usr/bin/mkdep -a -p ${INCLUDES} ${IDENT} ${PARAM} ${I386}/i386/genassym.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 $S/sys/param.h machine/pte.h $S/sys/buf.h \ + ${I386}/isa/isa_device.h ${I386}/isa/isa.h ${I386}/isa/icu.h + ${CC} -c ${CFLAGS} ioconf.c + +conf.o: $S/sys/param.h $S/sys/systm.h $S/sys/buf.h $S/sys/ioctl.h \ + $S/sys/tty.h $S/sys/conf.h \ + as.h bpfilter.h cd.h ch.h com.h dcfclk.h fd.h lpa.h \ + lpt.h pty.h sd.h speaker.h st.h wd.h wt.h \ + ${I386}/i386/conf.c + ${CC} -traditional -c ${CFLAGS} ${I386}/i386/conf.c + +param.c: $S/conf/param.c \ + $S/sys/param.h $S/sys/systm.h $S/sys/socket.h $S/sys/proc.h \ + $S/sys/vnode.h $S/sys/file.h $S/sys/callout.h $S/sys/clist.h \ + $S/sys/mbuf.h $S/ufs/quota.h $S/sys/kernel.h machine/vmparam.h \ + $S/sys/shm.h + -rm -f param.c + cp $S/conf/param.c . + +param.o: param.c Makefile + ${CC} -c ${CFLAGS} ${PARAM} param.c + +newvers: + sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT} + ${CC} ${CFLAGS} -c vers.c + +%RULES + +# DO NOT DELETE THIS LINE -- make depend uses it + diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 new file mode 100644 index 000000000000..578472cc73d2 --- /dev/null +++ b/sys/conf/files.i386 @@ -0,0 +1,71 @@ +# +# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE +# -------------------- ----- ---------------------- +# CURRENT PATCH LEVEL: 3 00160 +# -------------------- ----- ---------------------- +# +# 17 Feb 93 Julian Elischer Added files for scsi +# 10 Mar 93 Rodney W. Grimes Added files for lpt and lpa +# 25 Mar 93 Sean Eric Fagan Added microtime.s routine +# 08 Apr 93 Rodney W. Grimes Cleaned up the tabs, sorted file names +# Added ix, speaker, dcfclock +# 23 Apr 93 Holger Veit Added codrv +# 26 May 93 Rodney W. Grimes Rename of Bruce Evans com driver to sio +# Gene Stark Add xten power controler driver (tw) +# David Greenman Add ethernet driver (SMC/WD/3COM) (ed) +# Rick Macklem Add bus mouse driver (mse) +# +i386/i386/autoconf.c standard device-driver +i386/i386/cons.c standard +i386/i386/db_disasm.c optional ddb +i386/i386/db_interface.c optional ddb +i386/i386/db_trace.c optional ddb +i386/i386/in_cksum.c optional inet +i386/i386/machdep.c standard config-dependent +i386/i386/math_emulate.c standard +i386/i386/mem.c standard +i386/i386/microtime.s standard +i386/i386/ns_cksum.c optional ns +i386/i386/pmap.c standard +i386/i386/sys_machdep.c standard +i386/i386/trap.c standard +i386/i386/vm_machdep.c standard +i386/isa/aha1542.c optional aha device-driver +i386/isa/aha1742.c optional ahb device-driver +i386/isa/as.c optional as device-driver +i386/isa/bt742a.c optional bt device-driver +i386/isa/clock.c standard +i386/isa/codrv/co_cons.c optional co device-driver +i386/isa/codrv/co_kbd.c optional co device-driver +i386/isa/codrv/co_vga.c optional co device-driver +i386/isa/codrv/co_codrv1.c optional co device-driver +i386/isa/codrv/co_vty.c optional vty +i386/isa/codrv/co_pc3.c optional vtemul +i386/isa/codrv/co_mini.c optional vtemul +i386/isa/com.c optional com device-driver +i386/isa/dcfclk.c optional dcfclk device-driver +i386/isa/fd.c optional fd device-driver +i386/isa/if_ec.c optional ec device-driver +i386/isa/if_ed.c optional ed device-driver +i386/isa/if_is.c optional is device-driver +i386/isa/if_ix.c optional ix device-driver +i386/isa/if_ne.c optional ne device-driver +i386/isa/if_we.c optional we device-driver +i386/isa/isa.c optional isa device-driver +i386/isa/lpa.c optional lpa device-driver +i386/isa/lpt.c optional lpt device-driver +i386/isa/mse.c optional mse device-driver +i386/isa/npx.c optional npx device-driver +i386/isa/pccons.c optional pc device-driver +i386/isa/sio.c optional sio device-driver +i386/isa/spkr.c optional speaker +i386/isa/tw.c optional tw device-driver +i386/isa/ultra14f.c optional uha device-driver +i386/isa/wd.c optional wd device-driver +i386/isa/wt.c optional wt device-driver +scsi/cd.c optional cd +scsi/ch.c optional ch +scsi/scsiconf.c optional scbus +scsi/sd.c optional sd +scsi/st.c optional st + diff --git a/sys/ddb/db_access.c b/sys/ddb/db_access.c new file mode 100644 index 000000000000..63368c0cbc0c --- /dev/null +++ b/sys/ddb/db_access.c @@ -0,0 +1,116 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_access.c,v $ + * Revision 1.1 1992/03/25 21:44:50 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:05:44 mrt + * Changed to new Mach copyright + * [91/01/31 16:16:22 mrt] + * + * Revision 2.2 90/08/27 21:48:20 dbg + * Fix type declarations. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> /* type definitions */ + +/* + * Access unaligned data items on aligned (longword) + * boundaries. + */ + +extern void db_read_bytes(); /* machine-dependent */ +extern void db_write_bytes(); /* machine-dependent */ + +int db_extend[] = { /* table for sign-extending */ + 0, + 0xFFFFFF80, + 0xFFFF8000, + 0xFF800000 +}; + +db_expr_t +db_get_value(addr, size, is_signed) + db_addr_t addr; + register int size; + boolean_t is_signed; +{ + char data[sizeof(int)]; + register db_expr_t value; + register int i; + + db_read_bytes(addr, size, data); + + value = 0; +#if BYTE_MSF + for (i = 0; i < size; i++) +#else /* BYTE_LSF */ + for (i = size - 1; i >= 0; i--) +#endif + { + value = (value << 8) + (data[i] & 0xFF); + } + + if (size < 4) { + if (is_signed && (value & db_extend[size]) != 0) + value |= db_extend[size]; + } + return (value); +} + +void +db_put_value(addr, size, value) + db_addr_t addr; + register int size; + register db_expr_t value; +{ + char data[sizeof(int)]; + register int i; + +#if BYTE_MSF + for (i = size - 1; i >= 0; i--) +#else /* BYTE_LSF */ + for (i = 0; i < size; i++) +#endif + { + data[i] = value & 0xFF; + value >>= 8; + } + + db_write_bytes(addr, size, data); +} + diff --git a/sys/ddb/db_access.h b/sys/ddb/db_access.h new file mode 100644 index 000000000000..ddc5349148fa --- /dev/null +++ b/sys/ddb/db_access.h @@ -0,0 +1,55 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_access.h,v $ + * Revision 1.1 1992/03/25 21:44:53 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:05:49 mrt + * Changed to new Mach copyright + * [91/01/31 16:16:37 mrt] + * + * Revision 2.2 90/08/27 21:48:27 dbg + * Created. + * [90/08/07 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Data access functions for debugger. + */ +#include <machine/db_machdep.h> /* expression types */ + +extern db_expr_t db_get_value(/* db_addr_t addr, + int size, + boolean_t is_signed */); +extern void db_put_value(/* db_addr_t addr, + int size, + db_expr_t value */); diff --git a/sys/ddb/db_aout.c b/sys/ddb/db_aout.c new file mode 100644 index 000000000000..88f4b03e1858 --- /dev/null +++ b/sys/ddb/db_aout.c @@ -0,0 +1,309 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_aout.c,v $ + * Revision 1.1 1992/03/25 21:44:55 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:05:55 mrt + * Changed to new Mach copyright + * [91/01/31 16:16:44 mrt] + * + * Revision 2.2 90/08/27 21:48:35 dbg + * Created. + * [90/08/17 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Symbol table routines for a.out format files. + */ + +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> /* data types */ +#include <ddb/db_sym.h> + +#ifndef DB_NO_AOUT + +#define _AOUT_INCLUDE_ +#include "nlist.h" + +/* + * An a.out symbol table as loaded into the kernel debugger: + * + * symtab -> size of symbol entries, in bytes + * sp -> first symbol entry + * ... + * ep -> last symbol entry + 1 + * strtab == start of string table + * size of string table in bytes, + * including this word + * -> strings + */ + +/* + * Find pointers to the start and end of the symbol entries, + * given a pointer to the start of the symbol table. + */ +#define db_get_aout_symtab(symtab, sp, ep) \ + (sp = (struct nlist *)((symtab) + 1), \ + ep = (struct nlist *)((char *)sp + *(symtab))) + +#define SYMTAB_SPACE 63000 +int db_symtabsize = SYMTAB_SPACE; +char db_symtab[SYMTAB_SPACE] = { 1 }; + +X_db_sym_init(symtab, esymtab, name) + int * symtab; /* pointer to start of symbol table */ + char * esymtab; /* pointer to end of string table, + for checking - rounded up to integer + boundary */ + char * name; +{ + register struct nlist *sym_start, *sym_end; + register struct nlist *sp; + register char * strtab; + register int strlen; + + if (*symtab < 4) { + printf ("DDB: no symbols\n"); + return; + } + + db_get_aout_symtab(symtab, sym_start, sym_end); + + strtab = (char *)sym_end; + strlen = *(int *)strtab; + +#if 0 + if (strtab + ((strlen + sizeof(int) - 1) & ~(sizeof(int)-1)) + != esymtab) + { + db_printf("[ %s symbol table not valid ]\n", name); + return; + } + + db_printf("[ preserving %#x bytes of %s symbol table ]\n", + esymtab - (char *)symtab, name); +#endif + + for (sp = sym_start; sp < sym_end; sp++) { + register int strx; + strx = sp->n_un.n_strx; + if (strx != 0) { + if (strx > strlen) { + db_printf("Bad string table index (%#x)\n", strx); + sp->n_un.n_name = 0; + continue; + } + sp->n_un.n_name = strtab + strx; + } + } + + db_add_symbol_table(sym_start, sym_end, name, (char *)symtab); +} + +db_sym_t +X_db_lookup(stab, symstr) + db_symtab_t *stab; + char * symstr; +{ + register struct nlist *sp, *ep; + + sp = (struct nlist *)stab->start; + ep = (struct nlist *)stab->end; + + for (; sp < ep; sp++) { + if (sp->n_un.n_name == 0) + continue; + if ((sp->n_type & N_STAB) == 0 && + sp->n_un.n_name != 0 && + db_eqname(sp->n_un.n_name, symstr, '_')) + { + return ((db_sym_t)sp); + } + } + return ((db_sym_t)0); +} + +db_sym_t +X_db_search_symbol(symtab, off, strategy, diffp) + db_symtab_t * symtab; + register + db_addr_t off; + db_strategy_t strategy; + db_expr_t *diffp; /* in/out */ +{ + register unsigned int diff = *diffp; + register struct nlist *symp = 0; + register struct nlist *sp, *ep; + + sp = (struct nlist *)symtab->start; + ep = (struct nlist *)symtab->end; + + for (; sp < ep; sp++) { + if (sp->n_un.n_name == 0) + continue; + if ((sp->n_type & N_STAB) != 0) + continue; + if (off >= sp->n_value) { + if (off - sp->n_value < diff) { + diff = off - sp->n_value; + symp = sp; + if (diff == 0) + break; + } + else if (off - sp->n_value == diff) { + if (symp == 0) + symp = sp; + else if ((symp->n_type & N_EXT) == 0 && + (sp->n_type & N_EXT) != 0) + symp = sp; /* pick the external symbol */ + } + } + } + if (symp == 0) { + *diffp = off; + } + else { + *diffp = diff; + } + return ((db_sym_t)symp); +} + +/* + * Return the name and value for a symbol. + */ +void +X_db_symbol_values(sym, namep, valuep) + db_sym_t sym; + char **namep; + db_expr_t *valuep; +{ + register struct nlist *sp; + + sp = (struct nlist *)sym; + if (namep) + *namep = sp->n_un.n_name; + if (valuep) + *valuep = sp->n_value; +} + +boolean_t +X_db_line_at_pc() +{ + return (FALSE); +} + +/* + * Initialization routine for a.out files. + */ +kdb_init() +{ +#if 0 + extern char *esym; + extern int end; + + if (esym > (char *)&end) { + X_db_sym_init((int *)&end, esym, "mach"); + } +#endif + + X_db_sym_init (db_symtab, 0, "mach"); +} + +#if 0 +/* + * Read symbol table from file. + * (should be somewhere else) + */ +#include <boot_ufs/file_io.h> +#include <vm/vm_kern.h> + +read_symtab_from_file(fp, symtab_name) + struct file *fp; + char * symtab_name; +{ + vm_size_t resid; + kern_return_t result; + vm_offset_t symoff; + vm_size_t symsize; + vm_offset_t stroff; + vm_size_t strsize; + vm_size_t table_size; + vm_offset_t symtab; + + if (!get_symtab(fp, &symoff, &symsize)) { + boot_printf("[ error %d reading %s file header ]\n", + result, symtab_name); + return; + } + + stroff = symoff + symsize; + result = read_file(fp, (vm_offset_t)stroff, + (vm_offset_t)&strsize, sizeof(strsize), &resid); + if (result || resid) { + boot_printf("[ no valid symbol table present for %s ]\n", + symtab_name); + return; + } + + table_size = sizeof(int) + symsize + strsize; + table_size = (table_size + sizeof(int)-1) & ~(sizeof(int)-1); + + symtab = kmem_alloc_wired(kernel_map, table_size); + + *(int *)symtab = symsize; + + result = read_file(fp, symoff, + symtab + sizeof(int), symsize, &resid); + if (result || resid) { + boot_printf("[ error %d reading %s symbol table ]\n", + result, symtab_name); + return; + } + + result = read_file(fp, stroff, + symtab + sizeof(int) + symsize, strsize, &resid); + if (result || resid) { + boot_printf("[ error %d reading %s string table ]\n", + result, symtab_name); + return; + } + + X_db_sym_init((int *)symtab, + (char *)(symtab + table_size), + symtab_name); + +} +#endif + +#endif /* DB_NO_AOUT */ diff --git a/sys/ddb/db_break.c b/sys/ddb/db_break.c new file mode 100644 index 000000000000..9db7a041a111 --- /dev/null +++ b/sys/ddb/db_break.c @@ -0,0 +1,387 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_break.c,v $ + * Revision 1.1 1992/03/25 21:44:57 pace + * Initial revision + * + * Revision 2.7 91/02/05 17:06:00 mrt + * Changed to new Mach copyright + * [91/01/31 16:17:01 mrt] + * + * Revision 2.6 91/01/08 15:09:03 rpd + * Added db_map_equal, db_map_current, db_map_addr. + * [90/11/10 rpd] + * + * Revision 2.5 90/11/05 14:26:32 rpd + * Initialize db_breakpoints_inserted to TRUE. + * [90/11/04 rpd] + * + * Revision 2.4 90/10/25 14:43:33 rwd + * Added map field to breakpoints. + * Added map argument to db_set_breakpoint, db_delete_breakpoint, + * db_find_breakpoint. Added db_find_breakpoint_here. + * [90/10/18 rpd] + * + * Revision 2.3 90/09/28 16:57:07 jsb + * Fixed db_breakpoint_free. + * [90/09/18 rpd] + * + * Revision 2.2 90/08/27 21:49:53 dbg + * Reflected changes in db_printsym()'s calling seq. + * [90/08/20 af] + * Clear breakpoints only if inserted. + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Breakpoints. + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> /* type definitions */ + +#include <ddb/db_lex.h> +#include <ddb/db_break.h> +#include <ddb/db_access.h> +#include <ddb/db_sym.h> +#include <ddb/db_break.h> + +extern boolean_t db_map_equal(); +extern boolean_t db_map_current(); +extern vm_map_t db_map_addr(); + +#define NBREAKPOINTS 100 +struct db_breakpoint db_break_table[NBREAKPOINTS]; +db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; +db_breakpoint_t db_free_breakpoints = 0; +db_breakpoint_t db_breakpoint_list = 0; + +db_breakpoint_t +db_breakpoint_alloc() +{ + register db_breakpoint_t bkpt; + + if ((bkpt = db_free_breakpoints) != 0) { + db_free_breakpoints = bkpt->link; + return (bkpt); + } + if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { + db_printf("All breakpoints used.\n"); + return (0); + } + bkpt = db_next_free_breakpoint; + db_next_free_breakpoint++; + + return (bkpt); +} + +void +db_breakpoint_free(bkpt) + register db_breakpoint_t bkpt; +{ + bkpt->link = db_free_breakpoints; + db_free_breakpoints = bkpt; +} + +void +db_set_breakpoint(map, addr, count) + vm_map_t map; + db_addr_t addr; + int count; +{ + register db_breakpoint_t bkpt; + + if (db_find_breakpoint(map, addr)) { + db_printf("Already set.\n"); + return; + } + + bkpt = db_breakpoint_alloc(); + if (bkpt == 0) { + db_printf("Too many breakpoints.\n"); + return; + } + + bkpt->map = map; + bkpt->address = addr; + bkpt->flags = 0; + bkpt->init_count = count; + bkpt->count = count; + + bkpt->link = db_breakpoint_list; + db_breakpoint_list = bkpt; +} + +void +db_delete_breakpoint(map, addr) + vm_map_t map; + db_addr_t addr; +{ + register db_breakpoint_t bkpt; + register db_breakpoint_t *prev; + + for (prev = &db_breakpoint_list; + (bkpt = *prev) != 0; + prev = &bkpt->link) { + if (db_map_equal(bkpt->map, map) && + (bkpt->address == addr)) { + *prev = bkpt->link; + break; + } + } + if (bkpt == 0) { + db_printf("Not set.\n"); + return; + } + + db_breakpoint_free(bkpt); +} + +db_breakpoint_t +db_find_breakpoint(map, addr) + vm_map_t map; + db_addr_t addr; +{ + register db_breakpoint_t bkpt; + + for (bkpt = db_breakpoint_list; + bkpt != 0; + bkpt = bkpt->link) + { + if (db_map_equal(bkpt->map, map) && + (bkpt->address == addr)) + return (bkpt); + } + return (0); +} + +db_breakpoint_t +db_find_breakpoint_here(addr) + db_addr_t addr; +{ + return db_find_breakpoint(db_map_addr(addr), addr); +} + +boolean_t db_breakpoints_inserted = TRUE; + +void +db_set_breakpoints() +{ + register db_breakpoint_t bkpt; + + if (!db_breakpoints_inserted) { + + for (bkpt = db_breakpoint_list; + bkpt != 0; + bkpt = bkpt->link) + if (db_map_current(bkpt->map)) { + bkpt->bkpt_inst = db_get_value(bkpt->address, + BKPT_SIZE, + FALSE); + db_put_value(bkpt->address, + BKPT_SIZE, + BKPT_SET(bkpt->bkpt_inst)); + } + db_breakpoints_inserted = TRUE; + } +} + +void +db_clear_breakpoints() +{ + register db_breakpoint_t bkpt; + + if (db_breakpoints_inserted) { + + for (bkpt = db_breakpoint_list; + bkpt != 0; + bkpt = bkpt->link) + if (db_map_current(bkpt->map)) { + db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); + } + db_breakpoints_inserted = FALSE; + } +} + +/* + * Set a temporary breakpoint. + * The instruction is changed immediately, + * so the breakpoint does not have to be on the breakpoint list. + */ +db_breakpoint_t +db_set_temp_breakpoint(addr) + db_addr_t addr; +{ + register db_breakpoint_t bkpt; + + bkpt = db_breakpoint_alloc(); + if (bkpt == 0) { + db_printf("Too many breakpoints.\n"); + return 0; + } + + bkpt->map = NULL; + bkpt->address = addr; + bkpt->flags = BKPT_TEMP; + bkpt->init_count = 1; + bkpt->count = 1; + + bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE); + db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst)); + return bkpt; +} + +void +db_delete_temp_breakpoint(bkpt) + db_breakpoint_t bkpt; +{ + db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); + db_breakpoint_free(bkpt); +} + +/* + * List breakpoints. + */ +void +db_list_breakpoints() +{ + register db_breakpoint_t bkpt; + + if (db_breakpoint_list == 0) { + db_printf("No breakpoints set\n"); + return; + } + + db_printf(" Map Count Address\n"); + for (bkpt = db_breakpoint_list; + bkpt != 0; + bkpt = bkpt->link) + { + db_printf("%s%8x %5d ", + db_map_current(bkpt->map) ? "*" : " ", + bkpt->map, bkpt->init_count); + db_printsym(bkpt->address, DB_STGY_PROC); + db_printf("\n"); + } +} + +/* Delete breakpoint */ +/*ARGSUSED*/ +void +db_delete_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); +} + +/* Set breakpoint with skip count */ +/*ARGSUSED*/ +void +db_breakpoint_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + if (count == -1) + count = 1; + + db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); +} + +/* list breakpoints */ +void +db_listbreak_cmd() +{ + db_list_breakpoints(); +} + +#include <vm/vm_kern.h> + +/* + * We want ddb to be usable before most of the kernel has been + * initialized. In particular, current_thread() or kernel_map + * (or both) may be null. + */ + +boolean_t +db_map_equal(map1, map2) + vm_map_t map1, map2; +{ + return ((map1 == map2) || + ((map1 == NULL) && (map2 == kernel_map)) || + ((map1 == kernel_map) && (map2 == NULL))); +} + +boolean_t +db_map_current(map) + vm_map_t map; +{ +#if 0 + thread_t thread; + + return ((map == NULL) || + (map == kernel_map) || + (((thread = current_thread()) != NULL) && + (map == thread->task->map))); +#else + return (1); +#endif +} + +vm_map_t +db_map_addr(addr) + vm_offset_t addr; +{ +#if 0 + thread_t thread; + + /* + * We want to return kernel_map for all + * non-user addresses, even when debugging + * kernel tasks with their own maps. + */ + + if ((VM_MIN_ADDRESS <= addr) && + (addr < VM_MAX_ADDRESS) && + ((thread = current_thread()) != NULL)) + return thread->task->map; + else +#endif + return kernel_map; +} diff --git a/sys/ddb/db_break.h b/sys/ddb/db_break.h new file mode 100644 index 000000000000..874cbcb5c349 --- /dev/null +++ b/sys/ddb/db_break.h @@ -0,0 +1,84 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_break.h,v $ + * Revision 1.1 1992/03/25 21:44:59 pace + * Initial revision + * + * Revision 2.4 91/02/05 17:06:06 mrt + * Changed to new Mach copyright + * [91/01/31 16:17:10 mrt] + * + * Revision 2.3 90/10/25 14:43:40 rwd + * Added map field to breakpoints. + * [90/10/18 rpd] + * + * Revision 2.2 90/08/27 21:50:00 dbg + * Modularized typedef names. + * [90/08/20 af] + * Add external defintions. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +#ifndef _DDB_DB_BREAK_H_ +#define _DDB_DB_BREAK_H_ + +#include <vm/vm_map.h> +#include <machine/db_machdep.h> + +/* + * Breakpoint. + */ + +struct db_breakpoint { + vm_map_t map; /* in this map */ + db_addr_t address; /* set here */ + int init_count; /* number of times to skip bkpt */ + int count; /* current count */ + int flags; /* flags: */ +#define BKPT_SINGLE_STEP 0x2 /* to simulate single step */ +#define BKPT_TEMP 0x4 /* temporary */ + int bkpt_inst; /* saved instruction at bkpt */ + struct db_breakpoint *link; /* link in in-use or free chain */ +}; +typedef struct db_breakpoint *db_breakpoint_t; + +extern db_breakpoint_t db_find_breakpoint(); +extern db_breakpoint_t db_find_breakpoint_here(); +extern void db_set_breakpoints(); +extern void db_clear_breakpoints(); + +extern db_breakpoint_t db_set_temp_breakpoint(/* db_addr_t addr */); +extern void db_delete_temp_breakpoint(/* db_breakpoint_t bkpt */); + +#endif _DDB_DB_BREAK_H_ diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c new file mode 100644 index 000000000000..e660e183bd05 --- /dev/null +++ b/sys/ddb/db_command.c @@ -0,0 +1,526 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_command.c,v $ + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00081 + * -------------------- ----- ---------------------- + * + * 01 Feb 93 Julian Elischer move strcmp to a more general + * part of the kernel. + * + * Revision 1.1 1992/03/25 21:45:02 pace + * Initial revision + * + * Revision 2.6 91/02/05 17:06:10 mrt + * Changed to new Mach copyright + * [91/01/31 16:17:18 mrt] + * + * Revision 2.5 91/01/08 17:31:54 rpd + * Forward reference for db_fncall(); + * [91/01/04 12:35:17 rvb] + * + * Add call as a synonym for ! and match for next + * [91/01/04 12:14:48 rvb] + * + * Revision 2.4 90/11/07 16:49:15 rpd + * Added search. + * [90/11/06 rpd] + * + * Revision 2.3 90/10/25 14:43:45 rwd + * Changed db_fncall to print the result unsigned. + * [90/10/19 rpd] + * + * Added CS_MORE to db_watchpoint_cmd. + * [90/10/17 rpd] + * Added watchpoint commands: watch, dwatch, show watches. + * [90/10/16 rpd] + * + * Revision 2.2 90/08/27 21:50:10 dbg + * Remove 'listbreaks' - use 'show breaks' instead. Change 'show + * threads' to 'show all threads' to avoid clash with 'show thread'. + * Set 'dot' here from db_prev or db_next, depending on 'db_ed_style' + * flag and syntax table. + * [90/08/22 dbg] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Command dispatcher. + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> /* type definitions */ + +#include <ddb/db_lex.h> +#include <ddb/db_output.h> + +#include <setjmp.h> + +/* + * Exported global variables + */ +boolean_t db_cmd_loop_done; +jmp_buf db_jmpbuf; +db_addr_t db_dot; +db_addr_t db_last_addr; +db_addr_t db_prev; +db_addr_t db_next; + +/* + * if 'ed' style: 'dot' is set at start of last item printed, + * and '+' points to next line. + * Otherwise: 'dot' points to next item, '..' points to last. + */ +boolean_t db_ed_style = TRUE; + + +/* + * Utility routine - discard tokens through end-of-line. + */ +void +db_skip_to_eol() +{ + int t; + do { + t = db_read_token(); + } while (t != tEOL); +} + +/* + * Command table + */ +struct command { + char * name; /* command name */ + void (*fcn)(); /* function to call */ + int flag; /* extra info: */ +#define CS_OWN 0x1 /* non-standard syntax */ +#define CS_MORE 0x2 /* standard syntax, but may have other + words at end */ +#define CS_SET_DOT 0x100 /* set dot after command */ + struct command *more; /* another level of command */ +}; + +/* + * Results of command search. + */ +#define CMD_UNIQUE 0 +#define CMD_FOUND 1 +#define CMD_NONE 2 +#define CMD_AMBIGUOUS 3 +#define CMD_HELP 4 + +/* + * Search for command prefix. + */ +int +db_cmd_search(name, table, cmdp) + char * name; + struct command *table; + struct command **cmdp; /* out */ +{ + struct command *cmd; + int result = CMD_NONE; + + for (cmd = table; cmd->name != 0; cmd++) { + register char *lp; + register char *rp; + register int c; + + lp = name; + rp = cmd->name; + while ((c = *lp) == *rp) { + if (c == 0) { + /* complete match */ + *cmdp = cmd; + return (CMD_UNIQUE); + } + lp++; + rp++; + } + if (c == 0) { + /* end of name, not end of command - + partial match */ + if (result == CMD_FOUND) { + result = CMD_AMBIGUOUS; + /* but keep looking for a full match - + this lets us match single letters */ + } + else { + *cmdp = cmd; + result = CMD_FOUND; + } + } + } + if (result == CMD_NONE) { + /* check for 'help' */ + if (name[0] == 'h' && name[1] == 'e' + && name[2] == 'l' && name[3] == 'p') + result = CMD_HELP; + } + return (result); +} + +void +db_cmd_list(table) + struct command *table; +{ + register struct command *cmd; + + for (cmd = table; cmd->name != 0; cmd++) { + db_printf("%-12s", cmd->name); + db_end_line(); + } +} + +void +db_command(last_cmdp, cmd_table) + struct command **last_cmdp; /* IN_OUT */ + struct command *cmd_table; +{ + struct command *cmd; + int t; + char modif[TOK_STRING_SIZE]; + db_expr_t addr, count; + boolean_t have_addr; + int result; + + t = db_read_token(); + if (t == tEOL) { + /* empty line repeats last command, at 'next' */ + cmd = *last_cmdp; + addr = (db_expr_t)db_next; + have_addr = FALSE; + count = 1; + modif[0] = '\0'; + } + else if (t == tEXCL) { + void db_fncall(); + db_fncall(); + return; + } + else if (t != tIDENT) { + db_printf("?\n"); + db_flush_lex(); + return; + } + else { + /* + * Search for command + */ + while (cmd_table) { + result = db_cmd_search(db_tok_string, + cmd_table, + &cmd); + switch (result) { + case CMD_NONE: + db_printf("No such command\n"); + db_flush_lex(); + return; + case CMD_AMBIGUOUS: + db_printf("Ambiguous\n"); + db_flush_lex(); + return; + case CMD_HELP: + db_cmd_list(cmd_table); + db_flush_lex(); + return; + default: + break; + } + if ((cmd_table = cmd->more) != 0) { + t = db_read_token(); + if (t != tIDENT) { + db_cmd_list(cmd_table); + db_flush_lex(); + return; + } + } + } + + if ((cmd->flag & CS_OWN) == 0) { + /* + * Standard syntax: + * command [/modifier] [addr] [,count] + */ + t = db_read_token(); + if (t == tSLASH) { + t = db_read_token(); + if (t != tIDENT) { + db_printf("Bad modifier\n"); + db_flush_lex(); + return; + } + db_strcpy(modif, db_tok_string); + } + else { + db_unread_token(t); + modif[0] = '\0'; + } + + if (db_expression(&addr)) { + db_dot = (db_addr_t) addr; + db_last_addr = db_dot; + have_addr = TRUE; + } + else { + addr = (db_expr_t) db_dot; + have_addr = FALSE; + } + t = db_read_token(); + if (t == tCOMMA) { + if (!db_expression(&count)) { + db_printf("Count missing\n"); + db_flush_lex(); + return; + } + } + else { + db_unread_token(t); + count = -1; + } + if ((cmd->flag & CS_MORE) == 0) { + db_skip_to_eol(); + } + } + } + *last_cmdp = cmd; + if (cmd != 0) { + /* + * Execute the command. + */ + (*cmd->fcn)(addr, have_addr, count, modif); + + if (cmd->flag & CS_SET_DOT) { + /* + * If command changes dot, set dot to + * previous address displayed (if 'ed' style). + */ + if (db_ed_style) { + db_dot = db_prev; + } + else { + db_dot = db_next; + } + } + else { + /* + * If command does not change dot, + * set 'next' location to be the same. + */ + db_next = db_dot; + } + } +} + +/* + * 'show' commands + */ +extern void db_listbreak_cmd(); +extern void db_listwatch_cmd(); +extern void db_show_regs(), db_show_one_thread(), db_show_all_threads(); +extern void vm_map_print(), vm_object_print(), vm_page_print(); +extern void ipc_port_print(); +void db_show_help(); + +struct command db_show_all_cmds[] = { +#if 0 + { "threads", db_show_all_threads,0, 0 }, +#endif + { (char *)0 } +}; + +struct command db_show_cmds[] = { + { "all", 0, 0, db_show_all_cmds }, + { "registers", db_show_regs, 0, 0 }, + { "breaks", db_listbreak_cmd, 0, 0 }, + { "watches", db_listwatch_cmd, 0, 0 }, +#if 0 + { "thread", db_show_one_thread, 0, 0 }, +#endif + { "map", vm_map_print, 0, 0 }, + { "object", vm_object_print, 0, 0 }, +#if 0 + { "page", vm_page_print, 0, 0 }, +#endif +#if 0 + { "port", ipc_port_print, 0, 0 }, +#endif + { (char *)0, } +}; + +extern void db_print_cmd(), db_examine_cmd(), db_set_cmd(); +extern void db_search_cmd(); +extern void db_write_cmd(); +extern void db_delete_cmd(), db_breakpoint_cmd(); +extern void db_deletewatch_cmd(), db_watchpoint_cmd(); +extern void db_single_step_cmd(), db_trace_until_call_cmd(), + db_trace_until_matching_cmd(), db_continue_cmd(); +extern void db_stack_trace_cmd(); +void db_help_cmd(); +void db_fncall(); + +struct command db_command_table[] = { + { "print", db_print_cmd, 0, 0 }, + { "examine", db_examine_cmd, CS_SET_DOT, 0 }, + { "x", db_examine_cmd, CS_SET_DOT, 0 }, + { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 }, + { "set", db_set_cmd, CS_OWN, 0 }, + { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, + { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, + { "delete", db_delete_cmd, 0, 0 }, + { "d", db_delete_cmd, 0, 0 }, + { "break", db_breakpoint_cmd, 0, 0 }, + { "dwatch", db_deletewatch_cmd, 0, 0 }, + { "watch", db_watchpoint_cmd, CS_MORE,0 }, + { "step", db_single_step_cmd, 0, 0 }, + { "s", db_single_step_cmd, 0, 0 }, + { "continue", db_continue_cmd, 0, 0 }, + { "c", db_continue_cmd, 0, 0 }, + { "until", db_trace_until_call_cmd,0, 0 }, + { "next", db_trace_until_matching_cmd,0, 0 }, + { "match", db_trace_until_matching_cmd,0, 0 }, + { "trace", db_stack_trace_cmd, 0, 0 }, + { "call", db_fncall, CS_OWN, 0 }, + { "show", 0, 0, db_show_cmds }, + { (char *)0, } +}; + +struct command *db_last_command = 0; + +void +db_help_cmd() +{ + struct command *cmd = db_command_table; + + while (cmd->name != 0) { + db_printf("%-12s", cmd->name); + db_end_line(); + cmd++; + } +} + +void +db_command_loop() +{ + /* + * Initialize 'prev' and 'next' to dot. + */ + db_prev = db_dot; + db_next = db_dot; + + db_cmd_loop_done = 0; + while (!db_cmd_loop_done) { + + (void) setjmp(db_jmpbuf); + if (db_print_position() != 0) + db_printf("\n"); + + db_printf("db> "); + (void) db_read_line(); + + db_command(&db_last_command, db_command_table); + } +} + +void +db_error(s) + char *s; +{ + if (s) + db_printf(s); + db_flush_lex(); + longjmp(db_jmpbuf, 1); +} + + +/* + * Call random function: + * !expr(arg,arg,arg) + */ +void +db_fncall() +{ + db_expr_t fn_addr; +#define MAXARGS 11 + db_expr_t args[MAXARGS]; + int nargs = 0; + db_expr_t retval; + db_expr_t (*func)(); + int t; + + if (!db_expression(&fn_addr)) { + db_printf("Bad function\n"); + db_flush_lex(); + return; + } + func = (db_expr_t (*) ()) fn_addr; + + t = db_read_token(); + if (t == tLPAREN) { + if (db_expression(&args[0])) { + nargs++; + while ((t = db_read_token()) == tCOMMA) { + if (nargs == MAXARGS) { + db_printf("Too many arguments\n"); + db_flush_lex(); + return; + } + if (!db_expression(&args[nargs])) { + db_printf("Argument missing\n"); + db_flush_lex(); + return; + } + nargs++; + } + db_unread_token(t); + } + if (db_read_token() != tRPAREN) { + db_printf("?\n"); + db_flush_lex(); + return; + } + } + db_skip_to_eol(); + + while (nargs < MAXARGS) { + args[nargs++] = 0; + } + + retval = (*func)(args[0], args[1], args[2], args[3], args[4], + args[5], args[6], args[7], args[8], args[9] ); + db_printf("%#n\n", retval); +} diff --git a/sys/ddb/db_command.h b/sys/ddb/db_command.h new file mode 100644 index 000000000000..938a3d6a28a1 --- /dev/null +++ b/sys/ddb/db_command.h @@ -0,0 +1,67 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_command.h,v $ + * Revision 1.1 1992/03/25 21:45:05 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:06:15 mrt + * Changed to new Mach copyright + * [91/01/31 16:17:28 mrt] + * + * Revision 2.2 90/08/27 21:50:19 dbg + * Replace db_last_address_examined with db_prev, db_next. + * [90/08/22 dbg] + * Created. + * [90/08/07 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Command loop declarations. + */ + +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> + +extern void db_command_loop(); +extern void db_skip_to_eol(); + +extern void db_error(/* char * */); /* report error */ + +extern db_addr_t db_dot; /* current location */ +extern db_addr_t db_last_addr; /* last explicit address typed */ +extern db_addr_t db_prev; /* last address examined + or written */ +extern db_addr_t db_next; /* next address to be examined + or written */ + + diff --git a/sys/ddb/db_examine.c b/sys/ddb/db_examine.c new file mode 100644 index 000000000000..66f5f6858c0e --- /dev/null +++ b/sys/ddb/db_examine.c @@ -0,0 +1,364 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_examine.c,v $ + * Revision 1.1 1992/03/25 21:45:07 pace + * Initial revision + * + * Revision 2.4 91/02/05 17:06:20 mrt + * Changed to new Mach copyright + * [91/01/31 16:17:37 mrt] + * + * Revision 2.3 90/11/07 16:49:23 rpd + * Added db_search_cmd, db_search. + * [90/11/06 rpd] + * + * Revision 2.2 90/08/27 21:50:38 dbg + * Add 'r', 'z' to print and examine formats. + * Change calling sequence of db_disasm. + * db_examine sets db_prev and db_next instead of explicitly + * advancing dot. + * [90/08/20 dbg] + * Reflected changes in db_printsym()'s calling seq. + * [90/08/20 af] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> /* type definitions */ + +#include <ddb/db_lex.h> +#include <ddb/db_output.h> +#include <ddb/db_command.h> +#include <ddb/db_sym.h> + +char db_examine_format[TOK_STRING_SIZE] = "x"; + +extern db_addr_t db_disasm(/* db_addr_t, boolean_t */); + /* instruction disassembler */ + +/* + * Examine (print) data. + */ +/*ARGSUSED*/ +void +db_examine_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + if (modif[0] != '\0') + db_strcpy(db_examine_format, modif); + + if (count == -1) + count = 1; + + db_examine((db_addr_t) addr, db_examine_format, count); +} + +db_examine(addr, fmt, count) + register + db_addr_t addr; + char * fmt; /* format string */ + int count; /* repeat count */ +{ + int c; + db_expr_t value; + int size; + int width; + char * fp; + + while (--count >= 0) { + fp = fmt; + size = 4; + width = 16; + while ((c = *fp++) != 0) { + switch (c) { + case 'b': + size = 1; + width = 4; + break; + case 'h': + size = 2; + width = 8; + break; + case 'l': + size = 4; + width = 16; + break; + case 'a': /* address */ + /* always forces a new line */ + if (db_print_position() != 0) + db_printf("\n"); + db_prev = addr; + db_printsym(addr, DB_STGY_ANY); + db_printf(":\t"); + break; + default: + if (db_print_position() == 0) { + /* If we hit a new symbol, print it */ + char * name; + db_expr_t off; + + db_find_sym_and_offset(addr, &name, &off); + if (off == 0) + db_printf("%s:\t", name); + else + db_printf("\t\t"); + + db_prev = addr; + } + + switch (c) { + case 'r': /* signed, current radix */ + value = db_get_value(addr, size, TRUE); + addr += size; + db_printf("%-*r", width, value); + break; + case 'x': /* unsigned hex */ + value = db_get_value(addr, size, FALSE); + addr += size; + db_printf("%-*x", width, value); + break; + case 'z': /* signed hex */ + value = db_get_value(addr, size, TRUE); + addr += size; + db_printf("%-*z", width, value); + break; + case 'd': /* signed decimal */ + value = db_get_value(addr, size, TRUE); + addr += size; + db_printf("%-*d", width, value); + break; + case 'u': /* unsigned decimal */ + value = db_get_value(addr, size, FALSE); + addr += size; + db_printf("%-*u", width, value); + break; + case 'o': /* unsigned octal */ + value = db_get_value(addr, size, FALSE); + addr += size; + db_printf("%-*o", width, value); + break; + case 'c': /* character */ + value = db_get_value(addr, 1, FALSE); + addr += 1; + if (value >= ' ' && value <= '~') + db_printf("%c", value); + else + db_printf("\\%03o", value); + break; + case 's': /* null-terminated string */ + for (;;) { + value = db_get_value(addr, 1, FALSE); + addr += 1; + if (value == 0) + break; + if (value >= ' ' && value <= '~') + db_printf("%c", value); + else + db_printf("\\%03o", value); + } + break; + case 'i': /* instruction */ + addr = db_disasm(addr, FALSE); + break; + case 'I': /* instruction, alternate form */ + addr = db_disasm(addr, TRUE); + break; + default: + break; + } + if (db_print_position() != 0) + db_end_line(); + break; + } + } + } + db_next = addr; +} + +/* + * Print value. + */ +char db_print_format = 'x'; + +/*ARGSUSED*/ +void +db_print_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + db_expr_t value; + + if (modif[0] != '\0') + db_print_format = modif[0]; + + switch (db_print_format) { + case 'a': + db_printsym((db_addr_t)addr, DB_STGY_ANY); + break; + case 'r': + db_printf("%11r", addr); + break; + case 'x': + db_printf("%8x", addr); + break; + case 'z': + db_printf("%8z", addr); + break; + case 'd': + db_printf("%11d", addr); + break; + case 'u': + db_printf("%11u", addr); + break; + case 'o': + db_printf("%16o", addr); + break; + case 'c': + value = addr & 0xFF; + if (value >= ' ' && value <= '~') + db_printf("%c", value); + else + db_printf("\\%03o", value); + break; + } + db_printf("\n"); +} + +db_print_loc_and_inst(loc) + db_addr_t loc; +{ + db_printsym(loc, DB_STGY_PROC); + db_printf(":\t"); + (void) db_disasm(loc, TRUE); +} + +db_strcpy(dst, src) + register char *dst; + register char *src; +{ + while (*dst++ = *src++) + ; +} + +/* + * Search for a value in memory. + * Syntax: search [/bhl] addr value [mask] [,count] + */ +void +db_search_cmd() +{ + int t; + db_addr_t addr; + int size; + db_expr_t value; + db_expr_t mask; + unsigned int count; + + t = db_read_token(); + if (t == tSLASH) { + t = db_read_token(); + if (t != tIDENT) { + bad_modifier: + db_printf("Bad modifier\n"); + db_flush_lex(); + return; + } + + if (!strcmp(db_tok_string, "b")) + size = 1; + else if (!strcmp(db_tok_string, "h")) + size = 2; + else if (!strcmp(db_tok_string, "l")) + size = 4; + else + goto bad_modifier; + } else { + db_unread_token(t); + size = 4; + } + + if (!db_expression(&addr)) { + db_printf("Address missing\n"); + db_flush_lex(); + return; + } + + if (!db_expression(&value)) { + db_printf("Value missing\n"); + db_flush_lex(); + return; + } + + if (!db_expression(&mask)) + mask = 0xffffffff; + + t = db_read_token(); + if (t == tCOMMA) { + if (!db_expression(&count)) { + db_printf("Count missing\n"); + db_flush_lex(); + return; + } + } else { + db_unread_token(t); + count = -1; /* effectively forever */ + } + db_skip_to_eol(); + + db_search(addr, size, value, mask, count); +} + +db_search(addr, size, value, mask, count) + register + db_addr_t addr; + int size; + db_expr_t value; + db_expr_t mask; + unsigned int count; +{ + while (count-- != 0) { + db_prev = addr; + if ((db_get_value(addr, size, FALSE) & mask) == value) + break; + addr += size; + } + db_next = addr; +} diff --git a/sys/ddb/db_expr.c b/sys/ddb/db_expr.c new file mode 100644 index 000000000000..062662c48e8d --- /dev/null +++ b/sys/ddb/db_expr.c @@ -0,0 +1,248 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_expr.c,v $ + * Revision 1.1 1992/03/25 21:45:09 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:06:25 mrt + * Changed to new Mach copyright + * [91/01/31 16:17:46 mrt] + * + * Revision 2.2 90/08/27 21:50:57 dbg + * Use '..' instead of '$$' for db_prev. + * Use '+' for db_next. + * [90/08/22 dbg] + * + * Allow repeated unary operators. + * [90/08/20 dbg] + * + * Reflected back rename of db_symbol_value->db_value_of_name + * [90/08/20 af] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> +#include <ddb/db_lex.h> +#include <ddb/db_access.h> +#include <ddb/db_command.h> + +boolean_t +db_term(valuep) + db_expr_t *valuep; +{ + int t; + + t = db_read_token(); + if (t == tIDENT) { + if (!db_value_of_name(db_tok_string, valuep)) { + db_error("Symbol not found\n"); + /*NOTREACHED*/ + } + return (TRUE); + } + if (t == tNUMBER) { + *valuep = (db_expr_t)db_tok_number; + return (TRUE); + } + if (t == tDOT) { + *valuep = (db_expr_t)db_dot; + return (TRUE); + } + if (t == tDOTDOT) { + *valuep = (db_expr_t)db_prev; + return (TRUE); + } + if (t == tPLUS) { + *valuep = (db_expr_t) db_next; + return (TRUE); + } + if (t == tDITTO) { + *valuep = (db_expr_t)db_last_addr; + return (TRUE); + } + if (t == tDOLLAR) { + if (!db_get_variable(valuep)) + return (FALSE); + return (TRUE); + } + if (t == tLPAREN) { + if (!db_expression(valuep)) { + db_error("Syntax error\n"); + /*NOTREACHED*/ + } + t = db_read_token(); + if (t != tRPAREN) { + db_error("Syntax error\n"); + /*NOTREACHED*/ + } + return (TRUE); + } + db_unread_token(t); + return (FALSE); +} + +boolean_t +db_unary(valuep) + db_expr_t *valuep; +{ + int t; + + t = db_read_token(); + if (t == tMINUS) { + if (!db_unary(valuep)) { + db_error("Syntax error\n"); + /*NOTREACHED*/ + } + *valuep = -*valuep; + return (TRUE); + } + if (t == tSTAR) { + /* indirection */ + if (!db_unary(valuep)) { + db_error("Syntax error\n"); + /*NOTREACHED*/ + } + *valuep = db_get_value((db_addr_t)*valuep, sizeof(int), FALSE); + return (TRUE); + } + db_unread_token(t); + return (db_term(valuep)); +} + +boolean_t +db_mult_expr(valuep) + db_expr_t *valuep; +{ + db_expr_t lhs, rhs; + int t; + + if (!db_unary(&lhs)) + return (FALSE); + + t = db_read_token(); + while (t == tSTAR || t == tSLASH || t == tPCT || t == tHASH) { + if (!db_term(&rhs)) { + db_error("Syntax error\n"); + /*NOTREACHED*/ + } + if (t == tSTAR) + lhs *= rhs; + else { + if (rhs == 0) { + db_error("Divide by 0\n"); + /*NOTREACHED*/ + } + if (t == tSLASH) + lhs /= rhs; + else if (t == tPCT) + lhs %= rhs; + else + lhs = ((lhs+rhs-1)/rhs)*rhs; + } + t = db_read_token(); + } + db_unread_token(t); + *valuep = lhs; + return (TRUE); +} + +boolean_t +db_add_expr(valuep) + db_expr_t *valuep; +{ + db_expr_t lhs, rhs; + int t; + + if (!db_mult_expr(&lhs)) + return (FALSE); + + t = db_read_token(); + while (t == tPLUS || t == tMINUS) { + if (!db_mult_expr(&rhs)) { + db_error("Syntax error\n"); + /*NOTREACHED*/ + } + if (t == tPLUS) + lhs += rhs; + else + lhs -= rhs; + t = db_read_token(); + } + db_unread_token(t); + *valuep = lhs; + return (TRUE); +} + +boolean_t +db_shift_expr(valuep) + db_expr_t *valuep; +{ + db_expr_t lhs, rhs; + int t; + + if (!db_add_expr(&lhs)) + return (FALSE); + + t = db_read_token(); + while (t == tSHIFT_L || t == tSHIFT_R) { + if (!db_add_expr(&rhs)) { + db_error("Syntax error\n"); + /*NOTREACHED*/ + } + if (rhs < 0) { + db_error("Negative shift amount\n"); + /*NOTREACHED*/ + } + if (t == tSHIFT_L) + lhs <<= rhs; + else { + /* Shift right is unsigned */ + lhs = (unsigned) lhs >> rhs; + } + t = db_read_token(); + } + db_unread_token(t); + *valuep = lhs; + return (TRUE); +} + +int +db_expression(valuep) + db_expr_t *valuep; +{ + return (db_shift_expr(valuep)); +} diff --git a/sys/ddb/db_input.c b/sys/ddb/db_input.c new file mode 100644 index 000000000000..5ec7824c51d5 --- /dev/null +++ b/sys/ddb/db_input.c @@ -0,0 +1,268 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_input.c,v $ + * Revision 1.1 1992/03/25 21:45:10 pace + * Initial revision + * + * Revision 2.4 91/02/14 14:41:53 mrt + * Add input line editing. + * [90/11/11 dbg] + * + * Revision 2.3 91/02/05 17:06:32 mrt + * Changed to new Mach copyright + * [91/01/31 16:18:13 mrt] + * + * Revision 2.2 90/08/27 21:51:03 dbg + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +#include "param.h" +#include "proc.h" +#include <ddb/db_output.h> + +/* + * Character input and editing. + */ + +/* + * We don't track output position while editing input, + * since input always ends with a new-line. We just + * reset the line position at the end. + */ +char * db_lbuf_start; /* start of input line buffer */ +char * db_lbuf_end; /* end of input line buffer */ +char * db_lc; /* current character */ +char * db_le; /* one past last character */ + +#define CTRL(c) ((c) & 0x1f) +#define isspace(c) ((c) == ' ' || (c) == '\t') +#define BLANK ' ' +#define BACKUP '\b' + +void +db_putstring(s, count) + char *s; + int count; +{ + while (--count >= 0) + cnputc(*s++); +} + +void +db_putnchars(c, count) + int c; + int count; +{ + while (--count >= 0) + cnputc(c); +} + +/* + * Delete N characters, forward or backward + */ +#define DEL_FWD 0 +#define DEL_BWD 1 +void +db_delete(n, bwd) + int n; + int bwd; +{ + register char *p; + + if (bwd) { + db_lc -= n; + db_putnchars(BACKUP, n); + } + for (p = db_lc; p < db_le-n; p++) { + *p = *(p+n); + cnputc(*p); + } + db_putnchars(BLANK, n); + db_putnchars(BACKUP, db_le - db_lc); + db_le -= n; +} + +/* returns TRUE at end-of-line */ +int +db_inputchar(c) + int c; +{ + switch (c) { + case CTRL('b'): + /* back up one character */ + if (db_lc > db_lbuf_start) { + cnputc(BACKUP); + db_lc--; + } + break; + case CTRL('f'): + /* forward one character */ + if (db_lc < db_le) { + cnputc(*db_lc); + db_lc++; + } + break; + case CTRL('a'): + /* beginning of line */ + while (db_lc > db_lbuf_start) { + cnputc(BACKUP); + db_lc--; + } + break; + case CTRL('e'): + /* end of line */ + while (db_lc < db_le) { + cnputc(*db_lc); + db_lc++; + } + break; + case CTRL('h'): + case 0177: + /* erase previous character */ + if (db_lc > db_lbuf_start) + db_delete(1, DEL_BWD); + break; + case CTRL('d'): + /* erase next character */ + if (db_lc < db_le) + db_delete(1, DEL_FWD); + break; + case CTRL('k'): + /* delete to end of line */ + if (db_lc < db_le) + db_delete(db_le - db_lc, DEL_FWD); + break; + case CTRL('t'): + /* twiddle last 2 characters */ + if (db_lc >= db_lbuf_start + 2) { + c = db_lc[-2]; + db_lc[-2] = db_lc[-1]; + db_lc[-1] = c; + cnputc(BACKUP); + cnputc(BACKUP); + cnputc(db_lc[-2]); + cnputc(db_lc[-1]); + } + break; + case CTRL('r'): + db_putstring("^R\n", 3); + if (db_le > db_lbuf_start) { + db_putstring(db_lbuf_start, db_le - db_lbuf_start); + db_putnchars(BACKUP, db_le - db_lc); + } + break; + case '\n': + case '\r': + *db_le++ = c; + return (1); + default: + if (db_le == db_lbuf_end) { + cnputc('\007'); + } + else if (c >= ' ' && c <= '~') { + register char *p; + + for (p = db_le; p > db_lc; p--) + *p = *(p-1); + *db_lc++ = c; + db_le++; + cnputc(c); + db_putstring(db_lc, db_le - db_lc); + db_putnchars(BACKUP, db_le - db_lc); + } + break; + } + return (0); +} + +int +db_readline(lstart, lsize) + char * lstart; + int lsize; +{ + db_force_whitespace(); /* synch output position */ + + db_lbuf_start = lstart; + db_lbuf_end = lstart + lsize; + db_lc = lstart; + db_le = lstart; + + while (!db_inputchar(cngetc())) + continue; + + db_putchar('\n'); /* synch output position */ + + *db_le = 0; + return (db_le - db_lbuf_start); +} + +void +db_check_interrupt() +{ + register int c; + + c = cnmaygetc(); + switch (c) { + case -1: /* no character */ + return; + + case CTRL('c'): + db_error((char *)0); + /*NOTREACHED*/ + + case CTRL('s'): + do { + c = cnmaygetc(); + if (c == CTRL('c')) + db_error((char *)0); + } while (c != CTRL('q')); + break; + + default: + /* drop on floor */ + break; + } +} + +cnmaygetc () +{ + return (-1); +} + +/* called from kdb_trap in db_interface.c */ +cnpollc (flag) +{ +} diff --git a/sys/ddb/db_lex.c b/sys/ddb/db_lex.c new file mode 100644 index 000000000000..dcfd90038a82 --- /dev/null +++ b/sys/ddb/db_lex.c @@ -0,0 +1,295 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_lex.c,v $ + * Revision 1.1 1992/03/25 21:45:13 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:06:36 mrt + * Changed to new Mach copyright + * [91/01/31 16:18:20 mrt] + * + * Revision 2.2 90/08/27 21:51:10 dbg + * Add 'dotdot' token. + * [90/08/22 dbg] + * + * Allow backslash to quote any character into an identifier. + * Allow colon in identifier for symbol table qualification. + * [90/08/16 dbg] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Lexical analyzer. + */ +#include <ddb/db_lex.h> + +char db_line[120]; +char * db_lp, *db_endlp; + +int +db_read_line() +{ + int i; + + i = db_readline(db_line, sizeof(db_line)); + if (i == 0) + return (0); /* EOI */ + db_lp = db_line; + db_endlp = db_lp + i; + return (i); +} + +void +db_flush_line() +{ + db_lp = db_line; + db_endlp = db_line; +} + +int db_look_char = 0; + +int +db_read_char() +{ + int c; + + if (db_look_char != 0) { + c = db_look_char; + db_look_char = 0; + } + else if (db_lp >= db_endlp) + c = -1; + else + c = *db_lp++; + return (c); +} + +void +db_unread_char(c) +{ + db_look_char = c; +} + +int db_look_token = 0; + +void +db_unread_token(t) + int t; +{ + db_look_token = t; +} + +int +db_read_token() +{ + int t; + + if (db_look_token) { + t = db_look_token; + db_look_token = 0; + } + else + t = db_lex(); + return (t); +} + +int db_tok_number; +char db_tok_string[TOK_STRING_SIZE]; + +int db_radix = 16; + +void +db_flush_lex() +{ + db_flush_line(); + db_look_char = 0; + db_look_token = 0; +} + +int +db_lex() +{ + int c; + + c = db_read_char(); + while (c <= ' ' || c > '~') { + if (c == '\n' || c == -1) + return (tEOL); + c = db_read_char(); + } + + if (c >= '0' && c <= '9') { + /* number */ + int r, digit; + + if (c > '0') + r = db_radix; + else { + c = db_read_char(); + if (c == 'O' || c == 'o') + r = 8; + else if (c == 'T' || c == 't') + r = 10; + else if (c == 'X' || c == 'x') + r = 16; + else { + r = db_radix; + db_unread_char(c); + } + c = db_read_char(); + } + db_tok_number = 0; + for (;;) { + if (c >= '0' && c <= ((r == 8) ? '7' : '9')) + digit = c - '0'; + else if (r == 16 && ((c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f'))) { + if (c >= 'a') + digit = c - 'a' + 10; + else if (c >= 'A') + digit = c - 'A' + 10; + } + else + break; + db_tok_number = db_tok_number * r + digit; + c = db_read_char(); + } + if ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c == '_')) + { + db_error("Bad character in number\n"); + db_flush_lex(); + return (tEOF); + } + db_unread_char(c); + return (tNUMBER); + } + if ((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + c == '_' || c == '\\') + { + /* string */ + char *cp; + + cp = db_tok_string; + if (c == '\\') { + c = db_read_char(); + if (c == '\n' || c == -1) + db_error("Bad escape\n"); + } + *cp++ = c; + while (1) { + c = db_read_char(); + if ((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + c == '_' || c == '\\' || c == ':') + { + if (c == '\\') { + c = db_read_char(); + if (c == '\n' || c == -1) + db_error("Bad escape\n"); + } + *cp++ = c; + if (cp == db_tok_string+sizeof(db_tok_string)) { + db_error("String too long\n"); + db_flush_lex(); + return (tEOF); + } + continue; + } + else { + *cp = '\0'; + break; + } + } + db_unread_char(c); + return (tIDENT); + } + + switch (c) { + case '+': + return (tPLUS); + case '-': + return (tMINUS); + case '.': + c = db_read_char(); + if (c == '.') + return (tDOTDOT); + db_unread_char(c); + return (tDOT); + case '*': + return (tSTAR); + case '/': + return (tSLASH); + case '=': + return (tEQ); + case '%': + return (tPCT); + case '#': + return (tHASH); + case '(': + return (tLPAREN); + case ')': + return (tRPAREN); + case ',': + return (tCOMMA); + case '"': + return (tDITTO); + case '$': + return (tDOLLAR); + case '!': + return (tEXCL); + case '<': + c = db_read_char(); + if (c == '<') + return (tSHIFT_L); + db_unread_char(c); + break; + case '>': + c = db_read_char(); + if (c == '>') + return (tSHIFT_R); + db_unread_char(c); + break; + case -1: + return (tEOF); + } + db_printf("Bad character\n"); + db_flush_lex(); + return (tEOF); +} diff --git a/sys/ddb/db_lex.h b/sys/ddb/db_lex.h new file mode 100644 index 000000000000..56c55694994c --- /dev/null +++ b/sys/ddb/db_lex.h @@ -0,0 +1,89 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_lex.h,v $ + * Revision 1.1 1992/03/25 21:45:15 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:06:41 mrt + * Changed to new Mach copyright + * [91/01/31 16:18:28 mrt] + * + * Revision 2.2 90/08/27 21:51:16 dbg + * Add 'dotdot' token. + * [90/08/22 dbg] + * Export db_flush_lex. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Lexical analyzer. + */ +extern int db_read_line(); +extern void db_flush_line(); +extern int db_read_char(); +extern void db_unread_char(/* char c */); +extern int db_read_token(); +extern void db_unread_token(/* int t */); +extern void db_flush_lex(); + +extern int db_tok_number; +#define TOK_STRING_SIZE 120 +extern char db_tok_string[TOK_STRING_SIZE]; +extern int db_radix; + +#define tEOF (-1) +#define tEOL 1 +#define tNUMBER 2 +#define tIDENT 3 +#define tPLUS 4 +#define tMINUS 5 +#define tDOT 6 +#define tSTAR 7 +#define tSLASH 8 +#define tEQ 9 +#define tLPAREN 10 +#define tRPAREN 11 +#define tPCT 12 +#define tHASH 13 +#define tCOMMA 14 +#define tDITTO 15 +#define tDOLLAR 16 +#define tEXCL 17 +#define tSHIFT_L 18 +#define tSHIFT_R 19 +#define tDOTDOT 20 + + + + diff --git a/sys/ddb/db_output.c b/sys/ddb/db_output.c new file mode 100644 index 000000000000..fc8fca776693 --- /dev/null +++ b/sys/ddb/db_output.c @@ -0,0 +1,389 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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. + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 4 00083 + * -------------------- ----- ---------------------- + * + * 14 Mar 93 Chris G. Demetriou Fixed so that tab is not output, + * use spaces instead. + */ +/* + * HISTORY + * $Log: db_output.c,v $ + * Revision 1.1 1992/03/25 21:45:18 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:06:45 mrt + * Changed to new Mach copyright + * [91/01/31 16:18:41 mrt] + * + * Revision 2.2 90/08/27 21:51:25 dbg + * Put extra features of db_doprnt in _doprnt. + * [90/08/20 dbg] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +/* + * Printf and character output for debugger. + */ + +#include "param.h" +#include <machine/stdarg.h> + +/* + * Character output - tracks position in line. + * To do this correctly, we should know how wide + * the output device is - then we could zero + * the line position when the output device wraps + * around to the start of the next line. + * + * Instead, we count the number of spaces printed + * since the last printing character so that we + * don't print trailing spaces. This avoids most + * of the wraparounds. + */ +int db_output_position = 0; /* output column */ +int db_last_non_space = 0; /* last non-space character */ +int db_tab_stop_width = 8; /* how wide are tab stops? */ +#define NEXT_TAB(i) \ + ((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width) +int db_max_width = 80; /* output line width */ + +extern void db_check_interrupt(); + +/* + * Force pending whitespace. + */ +void +db_force_whitespace() +{ + register int last_print, next_tab; + + last_print = db_last_non_space; + while (last_print < db_output_position) { + next_tab = NEXT_TAB(last_print); + if (next_tab <= db_output_position) { + while (last_print < next_tab) { /* DON'T send a tab!!! */ + cnputc(' '); + last_print++; + } + } + else { + cnputc(' '); + last_print++; + } + } + db_last_non_space = db_output_position; +} + +/* + * Output character. Buffer whitespace. + */ +db_putchar(c) + int c; /* character to output */ +{ + if (c > ' ' && c <= '~') { + /* + * Printing character. + * If we have spaces to print, print them first. + * Use tabs if possible. + */ + db_force_whitespace(); + cnputc(c); + db_output_position++; + db_last_non_space = db_output_position; + } + else if (c == '\n') { + /* Return */ + cnputc(c); + db_output_position = 0; + db_last_non_space = 0; + db_check_interrupt(); + } + else if (c == '\t') { + /* assume tabs every 8 positions */ + db_output_position = NEXT_TAB(db_output_position); + } + else if (c == ' ') { + /* space */ + db_output_position++; + } + else if (c == '\007') { + /* bell */ + cnputc(c); + } + /* other characters are assumed non-printing */ +} + +/* + * Return output position + */ +int +db_print_position() +{ + return (db_output_position); +} + +/* + * End line if too long. + */ +void +db_end_line() +{ + if (db_output_position >= db_max_width) + db_printf("\n"); +} + +/* + * Printing + */ +extern int db_radix; + +/*VARARGS1*/ +db_printf(char *fmt, ...) +{ + va_list listp; + va_start(listp, fmt); + db_printf_guts (fmt, listp); + va_end(listp); +} + +/* alternate name */ + +/*VARARGS1*/ +kdbprintf(char *fmt, ...) +{ + va_list listp; + va_start(listp, fmt); + db_printf_guts (fmt, listp); + va_end(listp); +} + +/* + * Put a number (base <= 16) in a buffer in reverse order; return an + * optional length and a pointer to the NULL terminated (preceded?) + * buffer. + */ +static char * +db_ksprintn(ul, base, lenp) + register u_long ul; + register int base, *lenp; +{ /* A long in base 8, plus NULL. */ + static char buf[sizeof(long) * NBBY / 3 + 2]; + register char *p; + + p = buf; + do { + *++p = "0123456789abcdef"[ul % base]; + } while (ul /= base); + if (lenp) + *lenp = p - buf; + return (p); +} + +db_printf_guts(fmt, ap) + register const char *fmt; + va_list ap; +{ + register char *p; + register int ch, n; + u_long ul; + int base, lflag, tmp, width; + char padc; + int ladjust; + int sharpflag; + int neg; + + for (;;) { + padc = ' '; + width = 0; + while ((ch = *(u_char *)fmt++) != '%') { + if (ch == '\0') + return; + db_putchar(ch); + } + lflag = 0; + ladjust = 0; + sharpflag = 0; + neg = 0; +reswitch: switch (ch = *(u_char *)fmt++) { + case '0': + padc = '0'; + goto reswitch; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + for (width = 0;; ++fmt) { + width = width * 10 + ch - '0'; + ch = *fmt; + if (ch < '0' || ch > '9') + break; + } + goto reswitch; + case 'l': + lflag = 1; + goto reswitch; + case '-': + ladjust = 1; + goto reswitch; + case '#': + sharpflag = 1; + goto reswitch; + case 'b': + ul = va_arg(ap, int); + p = va_arg(ap, char *); + for (p = db_ksprintn(ul, *p++, NULL); ch = *p--;) + db_putchar(ch); + + if (!ul) + break; + + for (tmp = 0; n = *p++;) { + if (ul & (1 << (n - 1))) { + db_putchar(tmp ? ',' : '<'); + for (; (n = *p) > ' '; ++p) + db_putchar(n); + tmp = 1; + } else + for (; *p > ' '; ++p); + } + if (tmp) + db_putchar('>'); + break; + case '*': + width = va_arg (ap, int); + if (width < 0) { + ladjust = !ladjust; + width = -width; + } + goto reswitch; + case 'c': + db_putchar(va_arg(ap, int)); + break; + case 's': + p = va_arg(ap, char *); + width -= strlen (p); + if (!ladjust && width > 0) + while (width--) + db_putchar (padc); + while (ch = *p++) + db_putchar(ch); + if (ladjust && width > 0) + while (width--) + db_putchar (padc); + break; + case 'r': + ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); + if ((long)ul < 0) { + neg = 1; + ul = -(long)ul; + } + base = db_radix; + if (base < 8 || base > 16) + base = 10; + goto number; + case 'n': + ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); + base = db_radix; + if (base < 8 || base > 16) + base = 10; + goto number; + case 'd': + ul = lflag ? va_arg(ap, long) : va_arg(ap, int); + if ((long)ul < 0) { + neg = 1; + ul = -(long)ul; + } + base = 10; + goto number; + case 'o': + ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); + base = 8; + goto number; + case 'u': + ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); + base = 10; + goto number; + case 'z': + ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); + if ((long)ul < 0) { + neg = 1; + ul = -(long)ul; + } + base = 16; + goto number; + case 'x': + ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); + base = 16; +number: p = (char *)db_ksprintn(ul, base, &tmp); + if (sharpflag && ul != 0) { + if (base == 8) + tmp++; + else if (base == 16) + tmp += 2; + } + if (neg) + tmp++; + + if (!ladjust && width && (width -= tmp) > 0) + while (width--) + db_putchar(padc); + if (neg) + db_putchar ('-'); + if (sharpflag && ul != 0) { + if (base == 8) { + db_putchar ('0'); + } else if (base == 16) { + db_putchar ('0'); + db_putchar ('x'); + } + } + if (ladjust && width && (width -= tmp) > 0) + while (width--) + db_putchar(padc); + + while (ch = *p--) + db_putchar(ch); + break; + default: + db_putchar('%'); + if (lflag) + db_putchar('l'); + /* FALLTHROUGH */ + case '%': + db_putchar(ch); + } + } +} + diff --git a/sys/ddb/db_output.h b/sys/ddb/db_output.h new file mode 100644 index 000000000000..3ad599d8cc3e --- /dev/null +++ b/sys/ddb/db_output.h @@ -0,0 +1,53 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_output.h,v $ + * Revision 1.1 1992/03/25 21:45:20 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:06:49 mrt + * Changed to new Mach copyright + * [91/01/31 16:18:48 mrt] + * + * Revision 2.2 90/08/27 21:51:32 dbg + * Created. + * [90/08/07 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 8/90 + */ + +/* + * Printing routines for kernel debugger. + */ + +extern void db_force_whitespace(); +extern int db_print_position(); +extern void db_end_line(); +extern int db_printf(); diff --git a/sys/ddb/db_print.c b/sys/ddb/db_print.c new file mode 100644 index 000000000000..48eef38c6aa1 --- /dev/null +++ b/sys/ddb/db_print.c @@ -0,0 +1,104 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_print.c,v $ + * Revision 1.1 1992/03/25 21:45:22 pace + * Initial revision + * + * Revision 2.5 91/02/05 17:06:53 mrt + * Changed to new Mach copyright + * [91/01/31 16:18:56 mrt] + * + * Revision 2.4 90/10/25 14:43:54 rwd + * Changed db_show_regs to print unsigned. + * [90/10/19 rpd] + * Generalized the watchpoint support. + * [90/10/16 rwd] + * + * Revision 2.3 90/09/09 23:19:52 rpd + * Avoid totally incorrect guesses of symbol names for small values. + * [90/08/30 17:39:08 af] + * + * Revision 2.2 90/08/27 21:51:49 dbg + * Insist that 'show thread' be called with an explicit address. + * [90/08/22 dbg] + * + * Fix type for db_maxoff. + * [90/08/20 dbg] + * + * Do not dereference the "valuep" field of a variable directly, + * call the new db_read/write_variable functions instead. + * Reflected changes in symbol lookup functions. + * [90/08/20 af] + * Reduce lint. + * [90/08/10 14:33:44 dbg] + * + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +/* + * Miscellaneous printing. + */ +#include "param.h" +#include "proc.h" + +#include <machine/db_machdep.h> + +#include <ddb/db_lex.h> +#include <ddb/db_variables.h> +#include <ddb/db_sym.h> + +extern unsigned int db_maxoff; + +void +db_show_regs() +{ + int (*func)(); + register struct db_variable *regp; + db_expr_t value, offset; + char * name; + + for (regp = db_regs; regp < db_eregs; regp++) { + db_read_variable(regp, &value); + db_printf("%-12s%#10n", regp->name, value); + db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset); + if (name != 0 && offset <= db_maxoff && offset != value) { + db_printf("\t%s", name); + if (offset != 0) + db_printf("+%#r", offset); + } + db_printf("\n"); + } + db_print_loc_and_inst(PC_REGS(DDB_REGS)); +} + diff --git a/sys/ddb/db_run.c b/sys/ddb/db_run.c new file mode 100644 index 000000000000..b8e33aa75ec9 --- /dev/null +++ b/sys/ddb/db_run.c @@ -0,0 +1,426 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_run.c,v $ + * Revision 1.1 1992/03/25 21:45:24 pace + * Initial revision + * + * Revision 2.5 91/02/05 17:06:58 mrt + * Changed to new Mach copyright + * [91/01/31 16:19:05 mrt] + * + * Revision 2.4 91/01/08 15:09:10 rpd + * Fixed bug in db_restart_at_pc. + * [90/12/07 rpd] + * Added STEP_COUNT and count option to db_continue_cmd. + * Changed db_stop_at_pc to return (modified) is_breakpoint. + * Fixed db_stop_at_pc to print newlines in the right places. + * [90/11/27 rpd] + * + * Revision 2.3 90/10/25 14:43:59 rwd + * Changed db_find_breakpoint to db_find_breakpoint_here. + * [90/10/18 rpd] + * + * Fixed db_set_single_step to pass regs to branch_taken. + * Added watchpoint argument to db_restart_at_pc. + * [90/10/17 rpd] + * Generalized the watchpoint support. + * [90/10/16 rwd] + * Added watchpoint support. + * [90/10/16 rpd] + * + * Revision 2.2 90/08/27 21:51:59 dbg + * Fixed names for single-step functions. + * [90/08/20 af] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +/* + * Commands to run process. + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> + +#include <ddb/db_lex.h> +#include <ddb/db_break.h> +#include <ddb/db_access.h> + +int db_run_mode; +#define STEP_NONE 0 +#define STEP_ONCE 1 +#define STEP_RETURN 2 +#define STEP_CALLT 3 +#define STEP_CONTINUE 4 +#define STEP_INVISIBLE 5 +#define STEP_COUNT 6 + +boolean_t db_sstep_print; +int db_loop_count; +int db_call_depth; + +int db_inst_count; +int db_load_count; +int db_store_count; + +#ifndef db_set_single_step +void db_set_single_step(/* db_regs_t *regs */); /* forward */ +#endif +#ifndef db_clear_single_step +void db_clear_single_step(/* db_regs_t *regs */); +#endif + +boolean_t +db_stop_at_pc(is_breakpoint) + boolean_t *is_breakpoint; +{ + register db_addr_t pc; + register db_breakpoint_t bkpt; + + db_clear_single_step(DDB_REGS); + db_clear_breakpoints(); + db_clear_watchpoints(); + pc = PC_REGS(DDB_REGS); + +#ifdef FIXUP_PC_AFTER_BREAK + if (*is_breakpoint) { + /* + * Breakpoint trap. Fix up the PC if the + * machine requires it. + */ + FIXUP_PC_AFTER_BREAK + pc = PC_REGS(DDB_REGS); + } +#endif + + /* + * Now check for a breakpoint at this address. + */ + bkpt = db_find_breakpoint_here(pc); + if (bkpt) { + if (--bkpt->count == 0) { + bkpt->count = bkpt->init_count; + *is_breakpoint = TRUE; + return (TRUE); /* stop here */ + } + } else if (*is_breakpoint) { + ddb_regs.tf_eip += 1; + } + + *is_breakpoint = FALSE; + + if (db_run_mode == STEP_INVISIBLE) { + db_run_mode = STEP_CONTINUE; + return (FALSE); /* continue */ + } + if (db_run_mode == STEP_COUNT) { + return (FALSE); /* continue */ + } + if (db_run_mode == STEP_ONCE) { + if (--db_loop_count > 0) { + if (db_sstep_print) { + db_printf("\t\t"); + db_print_loc_and_inst(pc); + db_printf("\n"); + } + return (FALSE); /* continue */ + } + } + if (db_run_mode == STEP_RETURN) { + db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); + + /* continue until matching return */ + + if (!inst_trap_return(ins) && + (!inst_return(ins) || --db_call_depth != 0)) { + if (db_sstep_print) { + if (inst_call(ins) || inst_return(ins)) { + register int i; + + db_printf("[after %6d] ", db_inst_count); + for (i = db_call_depth; --i > 0; ) + db_printf(" "); + db_print_loc_and_inst(pc); + db_printf("\n"); + } + } + if (inst_call(ins)) + db_call_depth++; + return (FALSE); /* continue */ + } + } + if (db_run_mode == STEP_CALLT) { + db_expr_t ins = db_get_value(pc, sizeof(int), FALSE); + + /* continue until call or return */ + + if (!inst_call(ins) && + !inst_return(ins) && + !inst_trap_return(ins)) { + return (FALSE); /* continue */ + } + } + db_run_mode = STEP_NONE; + return (TRUE); +} + +void +db_restart_at_pc(watchpt) + boolean_t watchpt; +{ + register db_addr_t pc = PC_REGS(DDB_REGS); + + if ((db_run_mode == STEP_COUNT) || + (db_run_mode == STEP_RETURN) || + (db_run_mode == STEP_CALLT)) { + db_expr_t ins; + + /* + * We are about to execute this instruction, + * so count it now. + */ + + ins = db_get_value(pc, sizeof(int), FALSE); + db_inst_count++; + db_load_count += inst_load(ins); + db_store_count += inst_store(ins); +#ifdef SOFTWARE_SSTEP + /* XXX works on mips, but... */ + if (inst_branch(ins) || inst_call(ins)) { + ins = db_get_value(next_instr_address(pc,1), + sizeof(int), FALSE); + db_inst_count++; + db_load_count += inst_load(ins); + db_store_count += inst_store(ins); + } +#endif SOFTWARE_SSTEP + } + + if (db_run_mode == STEP_CONTINUE) { + if (watchpt || db_find_breakpoint_here(pc)) { + /* + * Step over breakpoint/watchpoint. + */ + db_run_mode = STEP_INVISIBLE; + db_set_single_step(DDB_REGS); + } else { + db_set_breakpoints(); + db_set_watchpoints(); + } + } else { + db_set_single_step(DDB_REGS); + } +} + +void +db_single_step(regs) + db_regs_t *regs; +{ + if (db_run_mode == STEP_CONTINUE) { + db_run_mode = STEP_INVISIBLE; + db_set_single_step(regs); + } +} + +#ifdef SOFTWARE_SSTEP +/* + * Software implementation of single-stepping. + * If your machine does not have a trace mode + * similar to the vax or sun ones you can use + * this implementation, done for the mips. + * Just define the above conditional and provide + * the functions/macros defined below. + * + * extern boolean_t + * inst_branch(), returns true if the instruction might branch + * extern unsigned + * branch_taken(), return the address the instruction might + * branch to + * db_getreg_val(); return the value of a user register, + * as indicated in the hardware instruction + * encoding, e.g. 8 for r8 + * + * next_instr_address(pc,bd) returns the address of the first + * instruction following the one at "pc", + * which is either in the taken path of + * the branch (bd==1) or not. This is + * for machines (mips) with branch delays. + * + * A single-step may involve at most 2 breakpoints - + * one for branch-not-taken and one for branch taken. + * If one of these addresses does not already have a breakpoint, + * we allocate a breakpoint and save it here. + * These breakpoints are deleted on return. + */ +db_breakpoint_t db_not_taken_bkpt = 0; +db_breakpoint_t db_taken_bkpt = 0; + +void +db_set_single_step(regs) + register db_regs_t *regs; +{ + db_addr_t pc = PC_REGS(regs); + register unsigned inst, brpc; + + /* + * User was stopped at pc, e.g. the instruction + * at pc was not executed. + */ + inst = db_get_value(pc, sizeof(int), FALSE); + if (inst_branch(inst) || inst_call(inst)) { + extern unsigned getreg_val(); + + brpc = branch_taken(inst, pc, getreg_val, regs); + if (brpc != pc) { /* self-branches are hopeless */ + db_taken_bkpt = db_set_temp_breakpoint(brpc); + } + pc = next_instr_address(pc,1); + } + pc = next_instr_address(pc,0); + db_not_taken_bkpt = db_set_temp_breakpoint(pc); +} + +void +db_clear_single_step(regs) + db_regs_t *regs; +{ + register db_breakpoint_t bkpt; + + if (db_taken_bkpt != 0) { + db_delete_temp_breakpoint(db_taken_bkpt); + db_taken_bkpt = 0; + } + if (db_not_taken_bkpt != 0) { + db_delete_temp_breakpoint(db_not_taken_bkpt); + db_not_taken_bkpt = 0; + } +} + +#endif SOFTWARE_SSTEP + +extern int db_cmd_loop_done; + +/* single-step */ +/*ARGSUSED*/ +void +db_single_step_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + boolean_t print = FALSE; + + if (count == -1) + count = 1; + + if (modif[0] == 'p') + print = TRUE; + + db_run_mode = STEP_ONCE; + db_loop_count = count; + db_sstep_print = print; + db_inst_count = 0; + db_load_count = 0; + db_store_count = 0; + + db_cmd_loop_done = 1; +} + +/* trace and print until call/return */ +/*ARGSUSED*/ +void +db_trace_until_call_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + boolean_t print = FALSE; + + if (modif[0] == 'p') + print = TRUE; + + db_run_mode = STEP_CALLT; + db_sstep_print = print; + db_inst_count = 0; + db_load_count = 0; + db_store_count = 0; + + db_cmd_loop_done = 1; +} + +/*ARGSUSED*/ +void +db_trace_until_matching_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + boolean_t print = FALSE; + + if (modif[0] == 'p') + print = TRUE; + + db_run_mode = STEP_RETURN; + db_call_depth = 1; + db_sstep_print = print; + db_inst_count = 0; + db_load_count = 0; + db_store_count = 0; + + db_cmd_loop_done = 1; +} + +/* continue */ +/*ARGSUSED*/ +void +db_continue_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + if (modif[0] == 'c') + db_run_mode = STEP_COUNT; + else + db_run_mode = STEP_CONTINUE; + db_inst_count = 0; + db_load_count = 0; + db_store_count = 0; + + db_cmd_loop_done = 1; +} diff --git a/sys/ddb/db_sym.c b/sys/ddb/db_sym.c new file mode 100644 index 000000000000..0517c68521ee --- /dev/null +++ b/sys/ddb/db_sym.c @@ -0,0 +1,360 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_sym.c,v $ + * Revision 1.1 1992/03/25 21:45:27 pace + * Initial revision + * + * Revision 2.5 91/02/05 17:07:07 mrt + * Changed to new Mach copyright + * [91/01/31 16:19:17 mrt] + * + * Revision 2.4 90/10/25 14:44:05 rwd + * Changed db_printsym to print unsigned. + * [90/10/19 rpd] + * + * Revision 2.3 90/09/09 23:19:56 rpd + * Avoid totally incorrect guesses of symbol names for small values. + * [90/08/30 17:39:48 af] + * + * Revision 2.2 90/08/27 21:52:18 dbg + * Removed nlist.h. Fixed some type declarations. + * Qualifier character is ':'. + * [90/08/20 dbg] + * Modularized symtab info into a new db_symtab_t type. + * Modified db_add_symbol_table and others accordingly. + * Defined db_sym_t, a new (opaque) type used to represent + * symbols. This should support all sort of future symtable + * formats. Functions like db_qualify take a db_sym_t now. + * New db_symbol_values() function to explode the content + * of a db_sym_t. + * db_search_symbol() replaces db_find_sym_and_offset(), which is + * now a macro defined in our (new) header file. This new + * function accepts more restrictive searches, which are + * entirely delegated to the symtab-specific code. + * Accordingly, db_printsym() accepts a strategy parameter. + * New db_line_at_pc() function. + * Renamed misleading db_eqsym into db_eqname. + * [90/08/20 10:47:06 af] + * + * Created. + * [90/07/25 dbg] + * + * Revision 2.1 90/07/26 16:43:52 dbg + * Created. + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> +#include <ddb/db_sym.h> + +/* + * We import from the symbol-table dependent routines: + */ +extern db_sym_t X_db_lookup(); +extern db_sym_t X_db_search_symbol(); +extern boolean_t X_db_line_at_pc(); +extern void X_db_symbol_values(); + +/* + * Multiple symbol tables + */ +#define MAXNOSYMTABS 3 /* mach, ux, emulator */ + +db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},}; +int db_nsymtab = 0; + +db_symtab_t *db_last_symtab; + +db_sym_t db_lookup(); /* forward */ + +/* + * Add symbol table, with given name, to list of symbol tables. + */ +void +db_add_symbol_table(start, end, name, ref) + char *start; + char *end; + char *name; + char *ref; +{ + if (db_nsymtab >= MAXNOSYMTABS) { + printf ("No slots left for %s symbol table", name); + panic ("db_sym.c: db_add_symbol_table"); + } + + db_symtabs[db_nsymtab].start = start; + db_symtabs[db_nsymtab].end = end; + db_symtabs[db_nsymtab].name = name; + db_symtabs[db_nsymtab].private = ref; + db_nsymtab++; +} + +/* + * db_qualify("vm_map", "ux") returns "unix:vm_map". + * + * Note: return value points to static data whose content is + * overwritten by each call... but in practice this seems okay. + */ +static char * +db_qualify(sym, symtabname) + db_sym_t sym; + register char *symtabname; +{ + char *symname; + static char tmp[256]; + register char *s; + + db_symbol_values(sym, &symname, 0); + s = tmp; + while (*s++ = *symtabname++) { + } + s[-1] = ':'; + while (*s++ = *symname++) { + } + return tmp; +} + + +boolean_t +db_eqname(src, dst, c) + char *src; + char *dst; + char c; +{ + if (!strcmp(src, dst)) + return (TRUE); + if (src[0] == c) + return (!strcmp(src+1,dst)); + return (FALSE); +} + +boolean_t +db_value_of_name(name, valuep) + char *name; + db_expr_t *valuep; +{ + db_sym_t sym; + + sym = db_lookup(name); + if (sym == DB_SYM_NULL) + return (FALSE); + db_symbol_values(sym, &name, valuep); + return (TRUE); +} + + +/* + * Lookup a symbol. + * If the symbol has a qualifier (e.g., ux:vm_map), + * then only the specified symbol table will be searched; + * otherwise, all symbol tables will be searched. + */ +db_sym_t +db_lookup(symstr) + char *symstr; +{ + db_sym_t sp; + register int i; + int symtab_start = 0; + int symtab_end = db_nsymtab; + register char *cp; + + /* + * Look for, remove, and remember any symbol table specifier. + */ + for (cp = symstr; *cp; cp++) { + if (*cp == ':') { + *cp = '\0'; + for (i = 0; i < db_nsymtab; i++) { + if (! strcmp(symstr, db_symtabs[i].name)) { + symtab_start = i; + symtab_end = i + 1; + break; + } + } + *cp = ':'; + if (i == db_nsymtab) { + db_error("invalid symbol table name"); + } + symstr = cp+1; + } + } + + /* + * Look in the specified set of symbol tables. + * Return on first match. + */ + for (i = symtab_start; i < symtab_end; i++) { + if (sp = X_db_lookup(&db_symtabs[i], symstr)) { + db_last_symtab = &db_symtabs[i]; + return sp; + } + } + return 0; +} + +/* + * Does this symbol name appear in more than one symbol table? + * Used by db_symbol_values to decide whether to qualify a symbol. + */ +boolean_t db_qualify_ambiguous_names = FALSE; + +boolean_t +db_symbol_is_ambiguous(sym) + db_sym_t sym; +{ + char *sym_name; + register int i; + register + boolean_t found_once = FALSE; + + if (!db_qualify_ambiguous_names) + return FALSE; + + db_symbol_values(sym, &sym_name, 0); + for (i = 0; i < db_nsymtab; i++) { + if (X_db_lookup(&db_symtabs[i], sym_name)) { + if (found_once) + return TRUE; + found_once = TRUE; + } + } + return FALSE; +} + +/* + * Find the closest symbol to val, and return its name + * and the difference between val and the symbol found. + */ +db_sym_t +db_search_symbol( val, strategy, offp) + register db_addr_t val; + db_strategy_t strategy; + db_expr_t *offp; +{ + register + unsigned int diff; + unsigned int newdiff; + register int i; + db_sym_t ret = DB_SYM_NULL, sym; + + newdiff = diff = ~0; + db_last_symtab = 0; + for (i = 0; i < db_nsymtab; i++) { + sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff); + if (newdiff < diff) { + db_last_symtab = &db_symtabs[i]; + diff = newdiff; + ret = sym; + } + } + *offp = diff; + return ret; +} + +/* + * Return name and value of a symbol + */ +void +db_symbol_values(sym, namep, valuep) + db_sym_t sym; + char **namep; + db_expr_t *valuep; +{ + db_expr_t value; + + if (sym == DB_SYM_NULL) { + *namep = 0; + return; + } + + X_db_symbol_values(sym, namep, &value); + + if (db_symbol_is_ambiguous(sym)) + *namep = db_qualify(sym, db_last_symtab->name); + if (valuep) + *valuep = value; +} + + +/* + * Print a the closest symbol to value + * + * After matching the symbol according to the given strategy + * we print it in the name+offset format, provided the symbol's + * value is close enough (eg smaller than db_maxoff). + * We also attempt to print [filename:linenum] when applicable + * (eg for procedure names). + * + * If we could not find a reasonable name+offset representation, + * then we just print the value in hex. Small values might get + * bogus symbol associations, e.g. 3 might get some absolute + * value like _INCLUDE_VERSION or something, therefore we do + * not accept symbols whose value is zero (and use plain hex). + */ + +unsigned int db_maxoff = 0x10000000; + +void +db_printsym(off, strategy) + db_expr_t off; + db_strategy_t strategy; +{ + db_expr_t d; + char *filename; + char *name; + db_expr_t value; + int linenum; + db_sym_t cursym; + + cursym = db_search_symbol(off, strategy, &d); + db_symbol_values(cursym, &name, &value); + if (name == 0 || d >= db_maxoff || value == 0) { + db_printf("%#n", off); + return; + } + db_printf("%s", name); + if (d) + db_printf("+%#r", d); + if (strategy == DB_STGY_PROC) { + if (db_line_at_pc(cursym, &filename, &linenum, off)) + db_printf(" [%s:%d]", filename, linenum); + } +} + + +boolean_t +db_line_at_pc( sym, filename, linenum, pc) +{ + return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc); +} diff --git a/sys/ddb/db_sym.h b/sys/ddb/db_sym.h new file mode 100644 index 000000000000..663f1cd4201a --- /dev/null +++ b/sys/ddb/db_sym.h @@ -0,0 +1,114 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_sym.h,v $ + * Revision 1.1 1992/03/25 21:45:29 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:07:12 mrt + * Changed to new Mach copyright + * [91/01/31 16:19:27 mrt] + * + * Revision 2.2 90/08/27 21:52:39 dbg + * Changed type of db_sym_t to char * - it's a better type for an + * opaque pointer. + * [90/08/22 dbg] + * + * Created. + * [90/08/19 af] + * + */ +/* + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 8/90 + */ + +/* + * This module can handle multiple symbol tables + */ +typedef struct { + char *name; /* symtab name */ + char *start; /* symtab location */ + char *end; + char *private; /* optional machdep pointer */ +} db_symtab_t; + +extern db_symtab_t *db_last_symtab; /* where last symbol was found */ + +/* + * Symbol representation is specific to the symtab style: + * BSD compilers use dbx' nlist, other compilers might use + * a different one + */ +typedef char * db_sym_t; /* opaque handle on symbols */ +#define DB_SYM_NULL ((db_sym_t)0) + +/* + * Non-stripped symbol tables will have duplicates, for instance + * the same string could match a parameter name, a local var, a + * global var, etc. + * We are most concern with the following matches. + */ +typedef int db_strategy_t; /* search strategy */ + +#define DB_STGY_ANY 0 /* anything goes */ +#define DB_STGY_XTRN 1 /* only external symbols */ +#define DB_STGY_PROC 2 /* only procedures */ + +extern boolean_t db_qualify_ambiguous_names; + /* if TRUE, check across symbol tables + * for multiple occurrences of a name. + * Might slow down quite a bit */ + +/* + * Functions exported by the symtable module + */ +extern void db_add_symbol_table(); + /* extend the list of symbol tables */ + +extern int db_value_of_name(/* char*, db_expr_t* */); + /* find symbol value given name */ + +extern db_sym_t db_search_symbol(/* db_expr_t, db_strategy_t, int* */); + /* find symbol given value */ + +extern void db_symbol_values(/* db_sym_t, char**, db_expr_t* */); + /* return name and value of symbol */ + +#define db_find_sym_and_offset(val,namep,offp) \ + db_symbol_values(db_search_symbol(val,DB_STGY_ANY,offp),namep,0) + /* find name&value given approx val */ + +#define db_find_xtrn_sym_and_offset(val,namep,offp) \ + db_symbol_values(db_search_symbol(val,DB_STGY_XTRN,offp),namep,0) + /* ditto, but no locals */ + +extern int db_eqname(/* char*, char*, char */); + /* strcmp, modulo leading char */ + +extern void db_printsym(/* db_expr_t, db_strategy_t */); + /* print closest symbol to a value */ diff --git a/sys/ddb/db_trap.c b/sys/ddb/db_trap.c new file mode 100644 index 000000000000..099fab143961 --- /dev/null +++ b/sys/ddb/db_trap.c @@ -0,0 +1,106 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_trap.c,v $ + * Revision 1.1 1992/03/25 21:45:31 pace + * Initial revision + * + * Revision 2.5 91/02/05 17:07:16 mrt + * Changed to new Mach copyright + * [91/01/31 16:19:35 mrt] + * + * Revision 2.4 91/01/08 15:09:17 rpd + * Changed db_stop_at_pc's arguments. + * Print db_inst_count, db_load_count, db_store_count. + * [90/11/27 rpd] + * + * Revision 2.3 90/10/25 14:44:11 rwd + * From rpd. + * [90/10/19 17:03:17 rwd] + * + * Generalized the watchpoint support. + * [90/10/16 rwd] + * Added watchpoint support. + * [90/10/16 rpd] + * + * Revision 2.2 90/08/27 21:52:52 dbg + * Assign to db_dot before calling the print function. + * [90/08/20 af] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +/* + * Trap entry point to kernel debugger. + */ +#include "param.h" +#include "proc.h" +#include <ddb/db_command.h> +#include <ddb/db_break.h> + +extern void db_restart_at_pc(); +extern boolean_t db_stop_at_pc(); + +extern int db_inst_count; +extern int db_load_count; +extern int db_store_count; + +db_trap(type, code) + int type, code; +{ + boolean_t bkpt; + boolean_t watchpt; + + bkpt = IS_BREAKPOINT_TRAP(type, code); + watchpt = IS_WATCHPOINT_TRAP(type, code); + + if (db_stop_at_pc(&bkpt)) { + if (db_inst_count) { + db_printf("After %d instructions (%d loads, %d stores),\n", + db_inst_count, db_load_count, db_store_count); + } + if (bkpt) + db_printf("Breakpoint at\t"); + else if (watchpt) + db_printf("Watchpoint at\t"); + else + db_printf("Stopped at\t"); + db_dot = PC_REGS(DDB_REGS); + db_print_loc_and_inst(db_dot); + + db_command_loop(); + } + + db_restart_at_pc(watchpt); +} diff --git a/sys/ddb/db_variables.c b/sys/ddb/db_variables.c new file mode 100644 index 000000000000..ed9512df5221 --- /dev/null +++ b/sys/ddb/db_variables.c @@ -0,0 +1,186 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_variables.c,v $ + * Revision 1.1 1992/03/25 21:45:33 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:07:19 mrt + * Changed to new Mach copyright + * [91/01/31 16:19:46 mrt] + * + * Revision 2.2 90/08/27 21:53:24 dbg + * New db_read/write_variable functions. Should be used instead + * of dereferencing valuep directly, which might not be a true + * pointer if there is an fcn() access function. + * [90/08/20 af] + * + * Fix declarations. + * Check for trailing garbage after last expression on command line. + * [90/08/10 14:34:54 dbg] + * + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> + +#include <ddb/db_lex.h> +#include <ddb/db_variables.h> + +extern unsigned int db_maxoff; + +extern int db_radix; +extern int db_max_width; +extern int db_tab_stop_width; + +struct db_variable db_vars[] = { + { "radix", &db_radix, FCN_NULL }, + { "maxoff", (int *)&db_maxoff, FCN_NULL }, + { "maxwidth", &db_max_width, FCN_NULL }, + { "tabstops", &db_tab_stop_width, FCN_NULL }, +}; +struct db_variable *db_evars = db_vars + sizeof(db_vars)/sizeof(db_vars[0]); + +int +db_find_variable(varp) + struct db_variable **varp; +{ + int t; + struct db_variable *vp; + + t = db_read_token(); + if (t == tIDENT) { + for (vp = db_vars; vp < db_evars; vp++) { + if (!strcmp(db_tok_string, vp->name)) { + *varp = vp; + return (1); + } + } + for (vp = db_regs; vp < db_eregs; vp++) { + if (!strcmp(db_tok_string, vp->name)) { + *varp = vp; + return (1); + } + } + } + db_error("Unknown variable\n"); + return (0); +} + +int +db_get_variable(valuep) + db_expr_t *valuep; +{ + struct db_variable *vp; + + if (!db_find_variable(&vp)) + return (0); + + db_read_variable(vp, valuep); + + return (1); +} + +int +db_set_variable(value) + db_expr_t value; +{ + struct db_variable *vp; + + if (!db_find_variable(&vp)) + return (0); + + db_write_variable(vp, &value); + + return (1); +} + + +db_read_variable(vp, valuep) + struct db_variable *vp; + db_expr_t *valuep; +{ + int (*func)() = vp->fcn; + + if (func == FCN_NULL) + *valuep = *(vp->valuep); + else + (*func)(vp, valuep, DB_VAR_GET); +} + +db_write_variable(vp, valuep) + struct db_variable *vp; + db_expr_t *valuep; +{ + int (*func)() = vp->fcn; + + if (func == FCN_NULL) + *(vp->valuep) = *valuep; + else + (*func)(vp, valuep, DB_VAR_SET); +} + +void +db_set_cmd() +{ + db_expr_t value; + int (*func)(); + struct db_variable *vp; + int t; + + t = db_read_token(); + if (t != tDOLLAR) { + db_error("Unknown variable\n"); + return; + } + if (!db_find_variable(&vp)) { + db_error("Unknown variable\n"); + return; + } + + t = db_read_token(); + if (t != tEQ) + db_unread_token(t); + + if (!db_expression(&value)) { + db_error("No value\n"); + return; + } + if (db_read_token() != tEOL) { + db_error("?\n"); + } + + db_write_variable(vp, &value); +} diff --git a/sys/ddb/db_variables.h b/sys/ddb/db_variables.h new file mode 100644 index 000000000000..f958d2c38349 --- /dev/null +++ b/sys/ddb/db_variables.h @@ -0,0 +1,72 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_variables.h,v $ + * Revision 1.1 1992/03/25 21:45:35 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:07:23 mrt + * Changed to new Mach copyright + * [91/01/31 16:19:54 mrt] + * + * Revision 2.2 90/08/27 21:53:40 dbg + * Modularized typedef name. Documented the calling sequence of + * the (optional) access function of a variable. Now the valuep + * field can be made opaque, eg be an offset that fcn() resolves. + * [90/08/20 af] + * + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +#ifndef _DB_VARIABLES_H_ +#define _DB_VARIABLES_H_ + +/* + * Debugger variables. + */ +struct db_variable { + char *name; /* Name of variable */ + int *valuep; /* value of variable */ + /* function to call when reading/writing */ + int (*fcn)(/* db_variable *vp, db_expr_t *valuep, int op */); +#define DB_VAR_GET 0 +#define DB_VAR_SET 1 +}; +#define FCN_NULL ((int (*)())0) + +extern struct db_variable db_vars[]; /* debugger variables */ +extern struct db_variable *db_evars; +extern struct db_variable db_regs[]; /* machine registers */ +extern struct db_variable *db_eregs; + +#endif /* _DB_VARIABLES_H_ */ diff --git a/sys/ddb/db_watch.c b/sys/ddb/db_watch.c new file mode 100644 index 000000000000..e69d906d93e7 --- /dev/null +++ b/sys/ddb/db_watch.c @@ -0,0 +1,294 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_watch.c,v $ + * Revision 1.1 1992/03/25 21:45:37 pace + * Initial revision + * + * Revision 2.5 91/02/05 17:07:27 mrt + * Changed to new Mach copyright + * [91/01/31 16:20:02 mrt] + * + * Revision 2.4 91/01/08 15:09:24 rpd + * Use db_map_equal, db_map_current, db_map_addr. + * [90/11/10 rpd] + * + * Revision 2.3 90/11/05 14:26:39 rpd + * Initialize db_watchpoints_inserted to TRUE. + * [90/11/04 rpd] + * + * Revision 2.2 90/10/25 14:44:16 rwd + * Made db_watchpoint_cmd parse a size argument. + * [90/10/17 rpd] + * Generalized the watchpoint support. + * [90/10/16 rwd] + * Created. + * [90/10/16 rpd] + * + */ +/* + * Author: Richard P. Draves, Carnegie Mellon University + * Date: 10/90 + */ + +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> + +#include <vm/vm_map.h> +#include <ddb/db_lex.h> +#include <ddb/db_watch.h> +#include <ddb/db_access.h> +#include <ddb/db_sym.h> +#include <machine/db_machdep.h> + +/* + * Watchpoints. + */ + +extern boolean_t db_map_equal(); +extern boolean_t db_map_current(); +extern vm_map_t db_map_addr(); + +boolean_t db_watchpoints_inserted = TRUE; + +#define NWATCHPOINTS 100 +struct db_watchpoint db_watch_table[NWATCHPOINTS]; +db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0]; +db_watchpoint_t db_free_watchpoints = 0; +db_watchpoint_t db_watchpoint_list = 0; + +db_watchpoint_t +db_watchpoint_alloc() +{ + register db_watchpoint_t watch; + + if ((watch = db_free_watchpoints) != 0) { + db_free_watchpoints = watch->link; + return (watch); + } + if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) { + db_printf("All watchpoints used.\n"); + return (0); + } + watch = db_next_free_watchpoint; + db_next_free_watchpoint++; + + return (watch); +} + +void +db_watchpoint_free(watch) + register db_watchpoint_t watch; +{ + watch->link = db_free_watchpoints; + db_free_watchpoints = watch; +} + +void +db_set_watchpoint(map, addr, size) + vm_map_t map; + db_addr_t addr; + vm_size_t size; +{ + register db_watchpoint_t watch; + + if (map == NULL) { + db_printf("No map.\n"); + return; + } + + /* + * Should we do anything fancy with overlapping regions? + */ + + for (watch = db_watchpoint_list; + watch != 0; + watch = watch->link) + if (db_map_equal(watch->map, map) && + (watch->loaddr == addr) && + (watch->hiaddr == addr+size)) { + db_printf("Already set.\n"); + return; + } + + watch = db_watchpoint_alloc(); + if (watch == 0) { + db_printf("Too many watchpoints.\n"); + return; + } + + watch->map = map; + watch->loaddr = addr; + watch->hiaddr = addr+size; + + watch->link = db_watchpoint_list; + db_watchpoint_list = watch; + + db_watchpoints_inserted = FALSE; +} + +void +db_delete_watchpoint(map, addr) + vm_map_t map; + db_addr_t addr; +{ + register db_watchpoint_t watch; + register db_watchpoint_t *prev; + + for (prev = &db_watchpoint_list; + (watch = *prev) != 0; + prev = &watch->link) + if (db_map_equal(watch->map, map) && + (watch->loaddr <= addr) && + (addr < watch->hiaddr)) { + *prev = watch->link; + db_watchpoint_free(watch); + return; + } + + db_printf("Not set.\n"); +} + +void +db_list_watchpoints() +{ + register db_watchpoint_t watch; + + if (db_watchpoint_list == 0) { + db_printf("No watchpoints set\n"); + return; + } + + db_printf(" Map Address Size\n"); + for (watch = db_watchpoint_list; + watch != 0; + watch = watch->link) + db_printf("%s%8x %8x %x\n", + db_map_current(watch->map) ? "*" : " ", + watch->map, watch->loaddr, + watch->hiaddr - watch->loaddr); +} + +/* Delete watchpoint */ +/*ARGSUSED*/ +void +db_deletewatch_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + db_delete_watchpoint(db_map_addr(addr), addr); +} + +/* Set watchpoint */ +/*ARGSUSED*/ +void +db_watchpoint_cmd(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + vm_size_t size; + db_expr_t value; + + if (db_expression(&value)) + size = (vm_size_t) value; + else + size = 4; + db_skip_to_eol(); + + db_set_watchpoint(db_map_addr(addr), addr, size); +} + +/* list watchpoints */ +void +db_listwatch_cmd() +{ + db_list_watchpoints(); +} + +void +db_set_watchpoints() +{ + register db_watchpoint_t watch; + + if (!db_watchpoints_inserted) { + for (watch = db_watchpoint_list; + watch != 0; + watch = watch->link) + pmap_protect(watch->map->pmap, + trunc_page(watch->loaddr), + round_page(watch->hiaddr), + VM_PROT_READ); + + db_watchpoints_inserted = TRUE; + } +} + +void +db_clear_watchpoints() +{ + db_watchpoints_inserted = FALSE; +} + +boolean_t +db_find_watchpoint(map, addr, regs) + vm_map_t map; + db_addr_t addr; + db_regs_t *regs; +{ + register db_watchpoint_t watch; + db_watchpoint_t found = 0; + + for (watch = db_watchpoint_list; + watch != 0; + watch = watch->link) + if (db_map_equal(watch->map, map)) { + if ((watch->loaddr <= addr) && + (addr < watch->hiaddr)) + return (TRUE); + else if ((trunc_page(watch->loaddr) <= addr) && + (addr < round_page(watch->hiaddr))) + found = watch; + } + + /* + * We didn't hit exactly on a watchpoint, but we are + * in a protected region. We want to single-step + * and then re-protect. + */ + + if (found) { + db_watchpoints_inserted = FALSE; + db_single_step(regs); + } + + return (FALSE); +} diff --git a/sys/ddb/db_watch.h b/sys/ddb/db_watch.h new file mode 100644 index 000000000000..9795755bfdcc --- /dev/null +++ b/sys/ddb/db_watch.h @@ -0,0 +1,74 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_watch.h,v $ + * Revision 1.1 1992/03/25 21:45:40 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:07:31 mrt + * Changed to new Mach copyright + * [91/01/31 16:20:09 mrt] + * + * Revision 2.2 90/10/25 14:44:21 rwd + * Generalized the watchpoint support. + * [90/10/16 rwd] + * Created. + * [90/10/16 rpd] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 10/90 + */ + +#ifndef _DDB_DB_WATCH_ +#define _DDB_DB_WATCH_ + +#include <vm/vm_map.h> +#include <machine/db_machdep.h> + +/* + * Watchpoint. + */ + +typedef struct db_watchpoint { + vm_map_t map; /* in this map */ + db_addr_t loaddr; /* from this address */ + db_addr_t hiaddr; /* to this address */ + struct db_watchpoint *link; /* link in in-use or free chain */ +} *db_watchpoint_t; + +extern boolean_t db_find_watchpoint(/* vm_map_t map, db_addr_t addr, + db_regs_t *regs */); +extern void db_set_watchpoints(); +extern void db_clear_watchpoints(); + +extern void db_set_watchpoint(/* vm_map_t map, db_addr_t addr, vm_size_t size */); +extern void db_delete_watchpoint(/* vm_map_t map, db_addr_t addr */); +extern void db_list_watchpoints(); + +#endif _DDB_DB_WATCH_ diff --git a/sys/ddb/db_write_cmd.c b/sys/ddb/db_write_cmd.c new file mode 100644 index 000000000000..dce22a915c78 --- /dev/null +++ b/sys/ddb/db_write_cmd.c @@ -0,0 +1,120 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_write_cmd.c,v $ + * Revision 1.1 1992/03/25 21:45:42 pace + * Initial revision + * + * Revision 2.4 91/02/05 17:07:35 mrt + * Changed to new Mach copyright + * [91/01/31 16:20:19 mrt] + * + * Revision 2.3 90/10/25 14:44:26 rwd + * Changed db_write_cmd to print unsigned. + * [90/10/19 rpd] + * + * Revision 2.2 90/08/27 21:53:54 dbg + * Set db_prev and db_next instead of explicitly advancing dot. + * [90/08/22 dbg] + * Reflected changes in db_printsym()'s calling seq. + * [90/08/20 af] + * Warn user if nothing was written. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> + +#include <ddb/db_lex.h> +#include <ddb/db_access.h> +#include <ddb/db_command.h> +#include <ddb/db_sym.h> + +/* + * Write to file. + */ +/*ARGSUSED*/ +void +db_write_cmd(address, have_addr, count, modif) + db_expr_t address; + boolean_t have_addr; + db_expr_t count; + char * modif; +{ + register + db_addr_t addr; + register + db_expr_t old_value; + db_expr_t new_value; + register int size; + boolean_t wrote_one = FALSE; + + addr = (db_addr_t) address; + + switch (modif[0]) { + case 'b': + size = 1; + break; + case 'h': + size = 2; + break; + case 'l': + case '\0': + size = 4; + break; + default: + db_error("Unknown size\n"); + return; + } + + while (db_expression(&new_value)) { + old_value = db_get_value(addr, size, FALSE); + db_printsym(addr, DB_STGY_ANY); + db_printf("\t\t%#8n\t=\t%#8n\n", old_value, new_value); + db_put_value(addr, size, new_value); + addr += size; + + wrote_one = TRUE; + } + + if (!wrote_one) + db_error("Nothing written.\n"); + + db_next = addr; + db_prev = addr - size; + + db_skip_to_eol(); +} + diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c new file mode 100644 index 000000000000..a461e8153dff --- /dev/null +++ b/sys/dev/fdc/fdc.c @@ -0,0 +1,903 @@ +/*#define DEBUG 1*/ +/*- + * 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 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00153 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Julian Elischer Heavily re worked, see notes below + * + * Largely rewritten to handle multiple controllers and drives + * By Julian Elischer, Sun Apr 4 16:34:33 WST 1993 + */ +char rev[] = "$Revision: 1.10 $"; +/* + * $Header: /usr/src/sys.386bsd/i386/isa/RCS/fd.c,v 1.10 93/04/13 16:53:29 root Exp $ + */ +/* + * $Log: fd.c,v $ + * Revision 1.10 93/04/13 16:53:29 root + * make sure turning off a drive motor doesn't deselect another + * drive active at the time. + * Also added a pointer from the fd_data to it's fd_type. + * + * Revision 1.9 93/04/13 15:31:02 root + * make all seeks go through DOSEEK state so are sure of being done right. + * + * Revision 1.8 93/04/12 21:20:13 root + * only check if old fd is the one we are working on if there IS + * an old fd pointer. (in fdstate()) + * + * Revision 1.7 93/04/11 17:05:35 root + * cleanup timeouts etc. + * also fix bug to select teh correct drive when running > 1 drive + * at a time. + * + * Revision 1.6 93/04/05 00:48:45 root + * change a timeout and add version to banner message + * + * Revision 1.5 93/04/04 16:39:08 root + * first working version.. some floppy controllers don't seem to + * like 2 int. status inquiries in a row. + * + */ + +#include "fd.h" +#if NFD > 0 + +#include "param.h" +#include "dkbad.h" +#include "systm.h" +#include "conf.h" +#include "file.h" +#include "ioctl.h" +#include "buf.h" +#include "uio.h" +#include "i386/isa/isa.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/fdreg.h" +#include "i386/isa/icu.h" +#include "i386/isa/rtc.h" +#undef NFD +#define NFD 2 + +#define FDUNIT(s) ((s>>3)&1) +#define FDTYPE(s) ((s)&7) + +#define b_cylin b_resid +#define FDBLK 512 +#define NUMTYPES 4 + +struct fd_type { + int sectrac; /* sectors per track */ + int secsize; /* size code for sectors */ + int datalen; /* data len when secsize = 0 */ + int gap; /* gap len between sectors */ + int tracks; /* total num of tracks */ + int size; /* size of disk in sectors */ + int steptrac; /* steps per cylinder */ + int trans; /* transfer speed code */ + int heads; /* number of heads */ +}; + +struct fd_type fd_types[NUMTYPES] = +{ + { 18,2,0xFF,0x1B,80,2880,1,0,2 }, /* 1.44 meg HD 3.5in floppy */ + { 15,2,0xFF,0x1B,80,2400,1,0,2 }, /* 1.2 meg HD floppy */ + { 9,2,0xFF,0x23,40,720,2,1,2 }, /* 360k floppy in 1.2meg drive */ + { 9,2,0xFF,0x2A,40,720,1,1,2 }, /* 360k floppy in DD drive */ +}; + +#define DRVS_PER_CTLR 2 +/***********************************************************************\ +* Per controller structure. * +\***********************************************************************/ +struct fdc_data +{ + int fdcu; /* our unit number */ + int baseport; + int dmachan; + int flags; +#define FDC_ATTACHED 0x01 + struct fd_data *fd; + int fdu; /* the active drive */ + struct buf head; /* Head of buf chain */ + struct buf rhead; /* Raw head of buf chain */ + int state; + int retry; + int status[7]; /* copy of the registers */ +}fdc_data[(NFD+1)/DRVS_PER_CTLR]; + +/***********************************************************************\ +* Per drive structure. * +* N per controller (presently 2) (DRVS_PER_CTLR) * +\***********************************************************************/ +struct fd_data { + struct fdc_data *fdc; + int fdu; /* this unit number */ + int fdsu; /* this units number on this controller */ + int type; /* Drive type (HD, DD */ + struct fd_type *ft; /* pointer to the type descriptor */ + int flags; +#define FD_OPEN 0x01 /* it's open */ +#define FD_ACTIVE 0x02 /* it's active */ +#define FD_MOTOR 0x04 /* motor should be on */ +#define FD_MOTOR_WAIT 0x08 /* motor coming up */ + int skip; + int hddrv; + int track; /* where we think the head is */ +} fd_data[NFD]; + +/***********************************************************************\ +* Throughout this file the following conventions will be used: * +* fd is a pointer to the fd_data struct for the drive in question * +* fdc is a pointer to the fdc_data struct for the controller * +* fdu is the floppy drive unit number * +* fdcu is the floppy controller unit number * +* fdsu is the floppy drive unit number on that controller. (sub-unit) * +\***********************************************************************/ +typedef int fdu_t; +typedef int fdcu_t; +typedef int fdsu_t; +typedef struct fd_data *fd_p; +typedef struct fdc_data *fdc_p; + +#define DEVIDLE 0 +#define FINDWORK 1 +#define DOSEEK 2 +#define SEEKCOMPLETE 3 +#define IOCOMPLETE 4 +#define RECALCOMPLETE 5 +#define STARTRECAL 6 +#define RESETCTLR 7 +#define SEEKWAIT 8 +#define RECALWAIT 9 +#define MOTORWAIT 10 +#define IOTIMEDOUT 11 + +#ifdef DEBUG +char *fdstates[] = +{ +"DEVIDLE", +"FINDWORK", +"DOSEEK", +"SEEKCOMPLETE", +"IOCOMPLETE", +"RECALCOMPLETE", +"STARTRECAL", +"RESETCTLR", +"SEEKWAIT", +"RECALWAIT", +"MOTORWAIT", +"IOTIMEDOUT" +}; + + +int fd_debug = 1; +#define TRACE0(arg) if(fd_debug) printf(arg) +#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2) +#else DEBUG +#define TRACE0(arg) +#define TRACE1(arg1,arg2) +#endif DEBUG + +extern int hz; +/* state needed for current transfer */ + +/****************************************************************************/ +/* autoconfiguration stuff */ +/****************************************************************************/ +int fdprobe(), fdattach(), fd_turnoff(); + +struct isa_driver fddriver = { + fdprobe, fdattach, "fd", +}; + +/* + * probe for existance of controller + */ +fdprobe(dev) +struct isa_device *dev; +{ + fdcu_t fdcu = dev->id_unit; + if(fdc_data[fdcu].flags & FDC_ATTACHED) + { + printf("fdc: same unit (%d) used multiple times\n",fdcu); + return 0; + } + + fdc_data[fdcu].baseport = dev->id_iobase; + + /* see if it can handle a command */ + if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0) + { + return(0); + } + out_fdc(fdcu,0xDF); + out_fdc(fdcu,2); + return (IO_FDCSIZE); +} + +/* + * wire controller into system, look for floppy units + */ +fdattach(dev) +struct isa_device *dev; +{ + unsigned fdt,st0, cyl; + int hdr; + fdu_t fdu; + fdcu_t fdcu = dev->id_unit; + fdc_p fdc = fdc_data + fdcu; + fd_p fd; + int fdsu; + + fdc->fdcu = fdcu; + fdc->flags |= FDC_ATTACHED; + fdc->dmachan = dev->id_drq; + fdc->state = DEVIDLE; + + fdt = rtcin(RTC_FDISKETTE); + hdr = 0; + + /* check for each floppy drive */ + for (fdu = (fdcu * DRVS_PER_CTLR),fdsu = 0; + ((fdu < NFD) && (fdsu < DRVS_PER_CTLR)); + fdu++,fdsu++) + { + /* is there a unit? */ + if ((fdt & 0xf0) == RTCFDT_NONE) + continue; + +#ifdef notyet + /* select it */ + fd_turnon1(fdu); + spinwait(1000); /* 1 sec */ + out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */ + out_fdc(fdcu,fdsu); + spinwait(1000); /* 1 sec */ + + /* anything responding */ + out_fdc(fdcu,NE7CMD_SENSEI); + st0 = in_fdc(fdcu); + cyl = in_fdc(fdcu); + if (st0 & 0xd0) + continue; + +#endif + fd_data[fdu].track = -2; + fd_data[fdu].fdc = fdc; + fd_data[fdu].fdsu = fdsu; + /* yes, announce it */ + if (!hdr) + printf(" drives "); + else + printf(", "); + printf("%d: ", fdu); + + + if ((fdt & 0xf0) == RTCFDT_12M) { + printf("1.2M"); + fd_data[fdu].type = 1; + fd_data[fdu].ft = fd_types + 1; + + } + if ((fdt & 0xf0) == RTCFDT_144M) { + printf("1.44M"); + fd_data[fdu].type = 0; + fd_data[fdu].ft = fd_types + 0; + } + + fdt <<= 4; + fd_turnoff(fdu); + hdr = 1; + } + + printf(" %s ",rev); + /* Set transfer to 500kbps */ + outb(fdc->baseport+fdctl,0); /*XXX*/ +} + +int +fdsize(dev) +dev_t dev; +{ + return(0); +} + +/****************************************************************************/ +/* fdstrategy */ +/****************************************************************************/ +fdstrategy(bp) + register struct buf *bp; /* IO operation to perform */ +{ + register struct buf *dp,*dp0,*dp1; + long nblocks,blknum; + int s; + fdcu_t fdcu; + fdu_t fdu; + fdc_p fdc; + fd_p fd; + + fdu = FDUNIT(minor(bp->b_dev)); + fd = &fd_data[fdu]; + fdc = fd->fdc; + fdcu = fdc->fdcu; + /*type = FDTYPE(minor(bp->b_dev));*/ + + if ((fdu >= NFD) || (bp->b_blkno < 0)) { + printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n", + fdu, bp->b_blkno, bp->b_bcount); + pg("fd:error in fdstrategy"); + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR; + goto bad; + } + /* + * Set up block calculations. + */ + blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK; + nblocks = fd->ft->size; + if (blknum + (bp->b_bcount / FDBLK) > nblocks) { + if (blknum == nblocks) { + bp->b_resid = bp->b_bcount; + } else { + bp->b_error = ENOSPC; + bp->b_flags |= B_ERROR; + } + goto bad; + } + bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads); + dp = &(fdc->head); + s = splbio(); + disksort(dp, bp); + untimeout(fd_turnoff,fdu); /* a good idea */ + fdstart(fdcu); + splx(s); + return; + +bad: + biodone(bp); +} + +/****************************************************************************/ +/* motor control stuff */ +/* remember to not deselect the drive we're working on */ +/****************************************************************************/ +set_motor(fdcu_t fdcu, fdu_t fdu, int reset) +{ + int m0,m1; + int selunit; + fd_p fd; + if(fd = fdc_data[fdcu].fd)/* yes an assign! */ + { + selunit = fd->fdsu; + } + else + { + selunit = 0; + } + m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR; + m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR; + outb(fdc_data[fdcu].baseport+fdout, + selunit + | (reset ? 0 : (FDO_FRST|FDO_FDMAEN)) + | (m0 ? FDO_MOEN0 : 0) + | (m1 ? FDO_MOEN1 : 0)); + TRACE1("[0x%x->fdout]",( + selunit + | (reset ? 0 : (FDO_FRST|FDO_FDMAEN)) + | (m0 ? FDO_MOEN0 : 0) + | (m1 ? FDO_MOEN1 : 0))); +} + +fd_turnoff(fdu_t fdu) +{ + fd_p fd = fd_data + fdu; + fd->flags &= ~FD_MOTOR; + set_motor(fd->fdc->fdcu,fd->fdsu,0); +} + +fd_motor_on(fdu_t fdu) +{ + fd_p fd = fd_data + fdu; + fd->flags &= ~FD_MOTOR_WAIT; + if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT)) + { + fd_pseudointr(fd->fdc->fdcu); + } +} + +fd_turnon(fdu_t fdu) +{ + fd_p fd = fd_data + fdu; + if(!(fd->flags & FD_MOTOR)) + { + fd_turnon1(fdu); + fd->flags |= FD_MOTOR_WAIT; + timeout(fd_motor_on,fdu,hz); /* in 1 sec its ok */ + } +} + +fd_turnon1(fdu_t fdu) +{ + fd_p fd = fd_data + fdu; + fd->flags |= FD_MOTOR; + set_motor(fd->fdc->fdcu,fd->fdsu,0); +} + +/****************************************************************************/ +/* fdc in/out */ +/****************************************************************************/ +int +in_fdc(fdcu_t fdcu) +{ + int baseport = fdc_data[fdcu].baseport; + int i, j = 100000; + while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM)) + != (NE7_DIO|NE7_RQM) && j-- > 0) + if (i == NE7_RQM) return -1; + if (j <= 0) + return(-1); +#ifdef DEBUG + i = inb(baseport+fddata); + TRACE1("[fddata->0x%x]",(unsigned char)i); + return(i); +#else + return inb(baseport+fddata); +#endif +} + +out_fdc(fdcu_t fdcu,int x) +{ + int baseport = fdc_data[fdcu].baseport; + int i = 100000; + + while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0); + while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0); + if (i <= 0) return (-1); + outb(baseport+fddata,x); + TRACE1("[0x%x->fddata]",x); + return (0); +} + +static fdopenf; +/****************************************************************************/ +/* fdopen/fdclose */ +/****************************************************************************/ +Fdopen(dev, flags) + dev_t dev; + int flags; +{ + fdu_t fdu = FDUNIT(minor(dev)); + /*int type = FDTYPE(minor(dev));*/ + int s; + + /* check bounds */ + if (fdu >= NFD) return(ENXIO); + /*if (type >= NUMTYPES) return(ENXIO);*/ + fd_data[fdu].flags |= FD_OPEN; + + return 0; +} + +fdclose(dev, flags) + dev_t dev; +{ + fdu_t fdu = FDUNIT(minor(dev)); + fd_data[fdu].flags &= ~FD_OPEN; + return(0); +} + + +/***************************************************************\ +* fdstart * +* We have just queued something.. if the controller is not busy * +* then simulate the case where it has just finished a command * +* So that it (the interrupt routine) looks on the queue for more* +* work to do and picks up what we just added. * +* If the controller is already busy, we need do nothing, as it * +* will pick up our work when the present work completes * +\***************************************************************/ +fdstart(fdcu_t fdcu) +{ + register struct buf *dp,*bp; + int s; + fdu_t fdu; + + s = splbio(); + if(fdc_data[fdcu].state == DEVIDLE) + { + fdintr(fdcu); + } + splx(s); +} + +fd_timeout(fdcu_t fdcu) +{ + fdu_t fdu = fdc_data[fdcu].fdu; + int st0, st3, cyl; + struct buf *dp,*bp; + + dp = &fdc_data[fdcu].head; + bp = dp->b_actf; + + out_fdc(fdcu,NE7CMD_SENSED); + out_fdc(fdcu,fd_data[fdu].hddrv); + st3 = in_fdc(fdcu); + + out_fdc(fdcu,NE7CMD_SENSEI); + st0 = in_fdc(fdcu); + cyl = in_fdc(fdcu); + printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n", + fdu, + st0, + NE7_ST0BITS, + cyl, + st3, + NE7_ST3BITS); + + if (bp) + { + retrier(fdcu); + fdc_data[fdcu].status[0] = 0xc0; + fdc_data[fdcu].state = IOTIMEDOUT; + if( fdc_data[fdcu].retry < 6) + fdc_data[fdcu].retry = 6; + } + else + { + fdc_data[fdcu].fd = (fd_p) 0; + fdc_data[fdcu].fdu = -1; + fdc_data[fdcu].state = DEVIDLE; + } + fd_pseudointr(fdcu); +} + +/* just ensure it has the right spl */ +fd_pseudointr(fdcu_t fdcu) +{ + int s; + s = splbio(); + fdintr(fdcu); + splx(s); +} + +/***********************************************************************\ +* fdintr * +* keep calling the state machine until it returns a 0 * +* ALWAYS called at SPLBIO * +\***********************************************************************/ +fdintr(fdcu_t fdcu) +{ + fdc_p fdc = fdc_data + fdcu; + while(fdstate(fdcu, fdc)); +} + +/***********************************************************************\ +* The controller state machine. * +* if it returns a non zero value, it should be called again immediatly * +\***********************************************************************/ +int fdstate(fdcu_t fdcu, fdc_p fdc) +{ + int read,head,trac,sec,i,s,sectrac,cyl,st0; + unsigned long blknum; + fdu_t fdu = fdc->fdu; + fd_p fd; + register struct buf *dp,*bp; + + dp = &(fdc->head); + bp = dp->b_actf; + if(!bp) + { + /***********************************************\ + * nothing left for this controller to do * + * Force into the IDLE state, * + \***********************************************/ + fdc->state = DEVIDLE; + if(fdc->fd) + { + printf("unexpected valid fd pointer (fdu = %d)\n" + ,fdc->fdu); + fdc->fd = (fd_p) 0; + fdc->fdu = -1; + } + TRACE1("[fdc%d IDLE]",fdcu); + return(0); + } + fdu = FDUNIT(minor(bp->b_dev)); + fd = fd_data + fdu; + if (fdc->fd && (fd != fdc->fd)) + { + printf("confused fd pointers\n"); + } + read = bp->b_flags & B_READ; + TRACE1("fd%d",fdu); + TRACE1("[%s]",fdstates[fdc->state]); + TRACE1("(0x%x)",fd->flags); + untimeout(fd_turnoff, fdu); + timeout(fd_turnoff,fdu,4 * hz); + switch (fdc->state) + { + case DEVIDLE: + case FINDWORK: /* we have found new work */ + fdc->retry = 0; + fd->skip = 0; + fdc->fd = fd; + fdc->fdu = fdu; + /*******************************************************\ + * If the next drive has a motor startup pending, then * + * it will start up in it's own good time * + \*******************************************************/ + if(fd->flags & FD_MOTOR_WAIT) + { + fdc->state = MOTORWAIT; + return(0); /* come back later */ + } + /*******************************************************\ + * Maybe if it's not starting, it SHOULD be starting * + \*******************************************************/ + if (!(fd->flags & FD_MOTOR)) + { + fdc->state = MOTORWAIT; + fd_turnon(fdu); + return(0); + } + else /* at least make sure we are selected */ + { + set_motor(fdcu,fd->fdsu,0); + } + fdc->state = DOSEEK; + break; + case DOSEEK: + if (bp->b_cylin == fd->track) + { + fdc->state = SEEKCOMPLETE; + break; + } + out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */ + out_fdc(fdcu,fd->fdsu); /* Drive number */ + out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac); + fd->track = -2; + fdc->state = SEEKWAIT; + return(0); /* will return later */ + case SEEKWAIT: + /* allow heads to settle */ + timeout(fd_pseudointr,fdcu,hz/50); + fdc->state = SEEKCOMPLETE; + return(0); /* will return later */ + break; + + case SEEKCOMPLETE : /* SEEK DONE, START DMA */ + /* Make sure seek really happened*/ + if(fd->track == -2) + { + int descyl = bp->b_cylin * fd->ft->steptrac; + out_fdc(fdcu,NE7CMD_SENSEI); + i = in_fdc(fdcu); + cyl = in_fdc(fdcu); + if (cyl != descyl) + { + printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", fdu, + descyl, cyl, i, NE7_ST0BITS); + return(retrier(fdcu)); + } + } + + fd->track = bp->b_cylin; + isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip, + FDBLK, fdc->dmachan); + blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK + + fd->skip/FDBLK; + sectrac = fd->ft->sectrac; + sec = blknum % (sectrac * fd->ft->heads); + head = sec / sectrac; + sec = sec % sectrac + 1; +/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu; + + if (read) + { + out_fdc(fdcu,NE7CMD_READ); /* READ */ + } + else + { + out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */ + } + out_fdc(fdcu,head << 2 | fdu); /* head & unit */ + out_fdc(fdcu,fd->track); /* track */ + out_fdc(fdcu,head); + out_fdc(fdcu,sec); /* sector XXX +1? */ + out_fdc(fdcu,fd->ft->secsize); /* sector size */ + out_fdc(fdcu,sectrac); /* sectors/track */ + out_fdc(fdcu,fd->ft->gap); /* gap size */ + out_fdc(fdcu,fd->ft->datalen); /* data length */ + fdc->state = IOCOMPLETE; + timeout(fd_timeout,fdcu,2 * hz); + return(0); /* will return later */ + case IOCOMPLETE: /* IO DONE, post-analyze */ + untimeout(fd_timeout,fdcu); + for(i=0;i<7;i++) + { + fdc->status[i] = in_fdc(fdcu); + } + case IOTIMEDOUT: /*XXX*/ + isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip, + FDBLK, fdc->dmachan); + if (fdc->status[0]&0xF8) + { + return(retrier(fdcu)); + } + /* All OK */ + fd->skip += FDBLK; + if (fd->skip < bp->b_bcount) + { + /* set up next transfer */ + blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK + + fd->skip/FDBLK; + bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads)); + fdc->state = DOSEEK; + } + else + { + /* ALL DONE */ + fd->skip = 0; + bp->b_resid = 0; + dp->b_actf = bp->av_forw; + biodone(bp); + fdc->fd = (fd_p) 0; + fdc->fdu = -1; + fdc->state = FINDWORK; + } + return(1); + case RESETCTLR: + /* Try a reset, keep motor on */ + set_motor(fdcu,fd->fdsu,1); + DELAY(100); + set_motor(fdcu,fd->fdsu,0); + outb(fdc->baseport+fdctl,fd->ft->trans); + TRACE1("[0x%x->fdctl]",fd->ft->trans); + fdc->retry++; + fdc->state = STARTRECAL; + break; + case STARTRECAL: + out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */ + out_fdc(fdcu,0xDF); + out_fdc(fdcu,2); + out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */ + out_fdc(fdcu,fdu); + fdc->state = RECALWAIT; + return(0); /* will return later */ + case RECALWAIT: + /* allow heads to settle */ + timeout(fd_pseudointr,fdcu,hz/30); + fdc->state = RECALCOMPLETE; + return(0); /* will return later */ + case RECALCOMPLETE: + out_fdc(fdcu,NE7CMD_SENSEI); + st0 = in_fdc(fdcu); + cyl = in_fdc(fdcu); + if (cyl != 0) + { + printf("fd%d: recal failed ST0 %b cyl %d\n", fdu, + st0, NE7_ST0BITS, cyl); + return(retrier(fdcu)); + } + fd->track = 0; + /* Seek (probably) necessary */ + fdc->state = DOSEEK; + return(1); /* will return immediatly */ + case MOTORWAIT: + if(fd->flags & FD_MOTOR_WAIT) + { + return(0); /* time's not up yet */ + } + fdc->state = DOSEEK; + return(1); /* will return immediatly */ + default: + printf("Unexpected FD int->"); + out_fdc(fdcu,NE7CMD_SENSEI); + st0 = in_fdc(fdcu); + cyl = in_fdc(fdcu); + printf("ST0 = %lx, PCN = %lx\n",i,sec); + out_fdc(fdcu,0x4A); + out_fdc(fdcu,fd->fdsu); + for(i=0;i<7;i++) { + fdc->status[i] = in_fdc(fdcu); + } + printf("intr status :%lx %lx %lx %lx %lx %lx %lx ", + fdc->status[0], + fdc->status[1], + fdc->status[2], + fdc->status[3], + fdc->status[4], + fdc->status[5], + fdc->status[6] ); + return(0); + } + return(1); /* Come back immediatly to new state */ +} + +retrier(fdcu_t fdcu) +{ + fdc_p fdc = fdc_data + fdcu; + register struct buf *dp,*bp; + + dp = &(fdc->head); + bp = dp->b_actf; + + switch(fdc->retry) + { + case 0: case 1: case 2: + fdc->state = SEEKCOMPLETE; + break; + case 3: case 4: case 5: + fdc->state = STARTRECAL; + break; + case 6: + fdc->state = RESETCTLR; + break; + case 7: + break; + default: + { + printf("fd%d: hard error (ST0 %b ", + fdc->fdu, fdc->status[0], NE7_ST0BITS); + printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS); + printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS); + printf(" ST3 %b ", fdc->status[3], NE7_ST3BITS); + printf("cyl %d hd %d sec %d)\n", + fdc->status[4], fdc->status[5], fdc->status[6]); + } + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + bp->b_resid = bp->b_bcount - fdc->fd->skip; + dp->b_actf = bp->av_forw; + fdc->fd->skip = 0; + biodone(bp); + fdc->state = FINDWORK; + fdc->fd = (fd_p) 0; + fdc->fdu = -1; + return(1); + } + fdc->retry++; + return(1); +} + +#endif + diff --git a/sys/dev/fdc/fdcreg.h b/sys/dev/fdc/fdcreg.h new file mode 100644 index 000000000000..948f566dfda8 --- /dev/null +++ b/sys/dev/fdc/fdcreg.h @@ -0,0 +1,72 @@ +/*- + * 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 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00153 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Julian Elischer Heavily re worked, see notes below + */ + +/* + * AT floppy controller registers and bitfields + */ + +/* uses NEC765 controller */ +#include "../i386/isa/ic/nec765.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_MOEN0 0x10 /* motor enable drive 0 */ +#define FDO_MOEN1 0x20 /* motor enable drive 1 */ +#define FDO_MOEN2 0x30 /* motor enable drive 2 */ +#define FDO_MOEN3 0x40 /* motor enable drive 3 */ + +#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 */ + + diff --git a/sys/dev/ic/i8237.h b/sys/dev/ic/i8237.h new file mode 100644 index 000000000000..dc269f2cfc2d --- /dev/null +++ b/sys/dev/ic/i8237.h @@ -0,0 +1,9 @@ +/* + * Intel 8237 DMA Controller + */ + +#define DMA37MD_SINGLE 0x40 /* single pass mode */ +#define DMA37MD_CASCADE 0xc0 /* cascade mode */ +#define DMA37MD_WRITE 0x04 /* read the device, write memory operation */ +#define DMA37MD_READ 0x08 /* write the device, read memory operation */ + diff --git a/sys/dev/ic/nec765.h b/sys/dev/ic/nec765.h new file mode 100644 index 000000000000..b84b46e799cf --- /dev/null +++ b/sys/dev/ic/nec765.h @@ -0,0 +1,71 @@ +/*- + * 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. + * + * @(#)nec765.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * Nec 765 floppy disc controller definitions + */ + +/* Main status register */ +#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */ +#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */ +#define NE7_CB 0x10 /* Diskette Controller Busy */ +#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */ +#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */ +#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */ + +/* Status register ST0 */ +#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head" + +/* Status register ST1 */ +#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am" + +/* Status register ST2 */ +#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam" + +/* Status register ST3 */ +#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002" + +/* Commands */ +#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit + parameters byte */ +#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */ +#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */ +#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */ +#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */ +#define NE7CMD_RECAL 7 /* recalibrate drive - requires + unit select byte */ +#define NE7CMD_SENSEI 8 /* sense controller interrupt status */ +#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte + and new cyl byte */ diff --git a/sys/dev/ic/ns16550.h b/sys/dev/ic/ns16550.h new file mode 100644 index 000000000000..e20e9aa58a89 --- /dev/null +++ b/sys/dev/ic/ns16550.h @@ -0,0 +1,50 @@ +/*- + * 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. + * + * @(#)ns16550.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * NS16550 UART registers + */ + +#define com_data 0 /* data register (R/W) */ +#define com_dlbl 0 /* divisor latch low (W) */ +#define com_dlbh 1 /* divisor latch high (W) */ +#define com_ier 1 /* interrupt enable (W) */ +#define com_iir 2 /* interrupt identification (R) */ +#define com_fifo 2 /* FIFO control (W) */ +#define com_lctl 3 /* line control register (R/W) */ +#define com_cfcr 3 /* line control register (R/W) */ +#define com_mcr 4 /* modem control register (R/W) */ +#define com_lsr 5 /* line status register (R/W) */ +#define com_msr 6 /* modem status register (R/W) */ diff --git a/sys/dev/sio/sio.c b/sys/dev/sio/sio.c new file mode 100644 index 000000000000..38503fd783bb --- /dev/null +++ b/sys/dev/sio/sio.c @@ -0,0 +1,1721 @@ +/*- + * 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. + * + * @(#)sio.c 7.5 (Berkeley) 5/16/91 + * + * 27 May 93 Bruce Evans From com-0.2 package, fast interrupt + * com port driver. + * 27 May 93 Guido van Rooij Ported in Chris Demetriou's BIDIR + * code, add multiport support. + * 27 May 93 Rodney W. Grimes I then renamed it to sio.c for putting + * into the patch kit. Added in sioselect + * from com.c. Added port 4 support. + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/isa/RCS/com.c,v 1.2 92/01/21 14:34:11 william Exp $"; + +#include "sio.h" +#if NSIO > 0 +/* + * COM driver, based on HP dca driver. + * Mostly rewritten to use pseudo-DMA. + * Works for National Semiconductor NS8250-NS16550AF UARTs. + */ +#include "param.h" +#include "systm.h" +#include "ioctl.h" +#include "tty.h" +#include "proc.h" +#include "user.h" +#include "conf.h" +#include "file.h" +#include "uio.h" +#include "kernel.h" +#include "syslog.h" + +#include "i386/isa/isa.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/comreg.h" +#include "i386/isa/ic/ns16550.h" + +#undef CRTS_IFLOW +#define CRTS_IFLOW CRTSCTS /* XXX, CCTS_OFLOW = CRTSCTS already */ +#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ +#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE) +#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8) +#define RS_IBUFSIZE 256 +#define TS_RTSBLOCK TS_TBLOCK /* XXX */ +#define TTY_BI TTY_FE /* XXX */ +#define TTY_OE TTY_PE /* XXX */ +#ifndef COM_BIDIR +#define UNIT(x) (minor(x)) /* XXX */ +#else /* COM_BIDIR */ +#define COM_UNITMASK 0x7f +#define COM_CALLOUTMASK 0x80 + +#define UNIT(x) (minor(x) & COM_UNITMASK) +#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK) +#endif /* COM_BIDIR */ + +#ifdef COM_MULTIPORT +/* checks in flags for multiport and which is multiport "master chip" + * for a given card + */ +#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01) +#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff) +#endif /* COM_MULTIPORT */ + +#define com_scr 7 /* scratch register for 16450-16550 (R/W) */ +#define schedsoftcom() (ipending |= 1 << 4) /* XXX */ + +/* + * Input buffer watermarks. + * The external device is asked to stop sending when the buffer exactly reaches + * high water, or when the high level requests it. + * The high level is notified immediately (rather than at a later clock tick) + * when this watermark is reached. + * The buffer size is chosen so the watermark should almost never be reached. + * The low watermark is invisibly 0 since the buffer is always emptied all at + * once. + */ +#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4) + +/* + * com state bits. + * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher + * than the other bits so that they can be tested as a group without masking + * off the low bits. + * + * The following com and tty flags correspond closely: + * TS_BUSY = CS_BUSY (maintained by comstart() and comflush()) + * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop()) + * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam()) + * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam()) + * TS_FLUSH is not used. + * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. + */ +#define CS_BUSY 0x80 /* output in progress */ +#define CS_TTGO 0x40 /* output not stopped by XOFF */ +#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */ +#define CS_CHECKMSR 1 /* check of MSR scheduled */ +#define CS_CTS_OFLOW 2 /* use CTS output flow control */ +#define CS_ODONE 4 /* output completed */ +#define CS_RTS_IFLOW 8 /* use RTS input flow control */ + +static char *error_desc[] = { +#define CE_OVERRUN 0 + "silo overflow", +#define CE_INTERRUPT_BUF_OVERFLOW 1 + "interrupt-level buffer overflow", +#define CE_TTY_BUF_OVERFLOW 2 + "tty-level buffer overflow", +}; + +#define CE_NTYPES 3 +#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum]) + +/* types. XXX - should be elsewhere */ +typedef u_int Port_t; /* hardware port */ +typedef int Bool_t; /* promoted boolean */ +typedef u_char bool_t; /* boolean */ + +/* com device structure */ +struct com_s { + u_char state; /* miscellaneous flag bits */ + u_char cfcr_image; /* copy of value written to CFCR */ + bool_t hasfifo; /* nonzero for 16550 UARTs */ + u_char mcr_image; /* copy of value written to MCR */ + bool_t softDCD; /* nonzero for faked carrier detect */ +#ifdef COM_BIDIR + bool_t bidir; /* is this unit bidirectional? */ + bool_t active; /* is the port active _at all_? */ + bool_t active_in; /* is the incoming port in use? */ + bool_t active_out; /* is the outgoing port in use? */ +#endif /* COM_BIDIR */ +#ifdef COM_MULTIPORT + bool_t multiport; /* is this unit part of a multiport device? */ +#endif /* COM_MULTIPORT */ + + /* + * The high level of the driver never reads status registers directly + * because there would be too many side effects to handle conveniently. + * Instead, it reads copies of the registers stored here by the + * interrupt handler. + */ + u_char last_modem_status; /* last MSR read by intr handler */ + u_char prev_modem_status; /* last MSR handled by high level */ + + u_char *ibuf; /* start of input buffer */ + u_char *ibufend; /* end of input buffer */ + u_char *ihighwater; /* threshold in input buffer */ + u_char *iptr; /* next free spot in input buffer */ + + u_char *obufend; /* end of output buffer */ + int ocount; /* original count for current output */ + u_char *optr; /* next char to output */ + + Port_t data_port; /* i/o ports */ + Port_t int_id_port; + Port_t iobase; + Port_t modem_ctl_port; + Port_t line_status_port; + Port_t modem_status_port; + + struct tty *tp; /* cross reference */ + + u_long bytes_in; /* statistics */ + u_long bytes_out; + u_int delta_error_counts[CE_NTYPES]; + u_int error_counts[CE_NTYPES]; + + /* + * Ping-pong input buffers. The extra factor of 2 in the sizes is + * to allow for an error byte for each input byte. + */ +#define CE_INPUT_OFFSET RS_IBUFSIZE + u_char ibuf1[2 * RS_IBUFSIZE]; + u_char ibuf2[2 * RS_IBUFSIZE]; +}; + + +/* + * These functions in the com module ought to be declared (with a prototype) + * in a com-driver system header. The void ones may need to be int to match + * ancient devswitch declarations, but they don't actually return anything. + */ +#define Dev_t int /* promoted dev_t */ +struct consdev; + +int sioclose __P((Dev_t dev, int fflag, int devtype, + struct proc *p)); +void siointr __P((int unit)); +#ifdef COM_MULTIPORT +bool_t comintr1 __P((struct com_s *com)); +#endif /* COM_MULTIPORT */ +int sioioctl __P((Dev_t dev, int cmd, caddr_t data, + int fflag, struct proc *p)); +int siocngetc __P((Dev_t dev)); +void siocninit __P((struct consdev *cp)); +void siocnprobe __P((struct consdev *cp)); +void siocnputc __P((Dev_t dev, int c)); +int sioopen __P((Dev_t dev, int oflags, int devtype, + struct proc *p)); +/* + * sioopen gets compared to the d_open entry in struct cdevsw. d_open and + * other functions are declared in <sys/conf.h> with short types like dev_t + * in the prototype. Such declarations are broken because they vary with + * __P (significantly in theory - the compiler is allowed to push a short + * arg if it has seen the prototype; insignificantly in practice - gcc + * doesn't push short args and it would be slower on 386's to do so). + * + * Also, most of the device switch functions are still declared old-style + * so they take a Dev_t arg and shorten it to a dev_t. It would be simpler + * and faster if dev_t's were always promoted (to ints or whatever) as + * early as possible. + * + * Until <sys/conf.h> is fixed, we cast sioopen to the following `wrong' type + * when comparing it to the d_open entry just to avoid compiler warnings. + */ +typedef int (*bogus_open_t) __P((dev_t dev, int oflags, int devtype, + struct proc *p)); +int sioread __P((Dev_t dev, struct uio *uio, int ioflag)); +void siostop __P((struct tty *tp, int rw)); +int siowrite __P((Dev_t dev, struct uio *uio, int ioflag)); +void softsio0 __P((void)); +void softsio1 __P((void)); +void softsio2 __P((void)); +void softsio3 __P((void)); +void softsio4 __P((void)); +void softsio5 __P((void)); +void softsio6 __P((void)); +void softsio7 __P((void)); +void softsio8 __P((void)); + +static int sioattach __P((struct isa_device *dev)); +static void comflush __P((struct com_s *com)); +static void comhardclose __P((struct com_s *com)); +static void cominit __P((int unit, int rate)); +static int commctl __P((struct com_s *com, int bits, int how)); +static int comparam __P((struct tty *tp, struct termios *t)); +static int sioprobe __P((struct isa_device *dev)); +static void compoll __P((void)); +static int comstart __P((struct tty *tp)); +static void comwakeup __P((void)); + +/* table and macro for fast conversion from a unit number to its com struct */ +static struct com_s *p_com_addr[NSIO]; +#define com_addr(unit) (p_com_addr[unit]) + +static struct com_s com_structs[NSIO]; + +struct isa_driver siodriver = { + sioprobe, sioattach, "sio" +}; + +#ifdef COMCONSOLE +static int comconsole = COMCONSOLE; +#else +static int comconsole = -1; +#endif +static bool_t comconsinit; +static speed_t comdefaultrate = TTYDEF_SPEED; +static u_int com_events; /* input chars + weighted output completions */ +static int commajor; +struct tty sio_tty[NSIO]; +extern struct tty *constty; +extern u_int ipending; /* XXX */ +extern int tk_nin; /* XXX */ +extern int tk_rawcc; /* XXX */ + +#ifdef KGDB +#include "machine/remote-sl.h" + +extern int kgdb_dev; +extern int kgdb_rate; +extern int kgdb_debug_init; +#endif + +static struct speedtab comspeedtab[] = { + 0, 0, + 50, COMBRD(50), + 75, COMBRD(75), + 110, COMBRD(110), + 134, COMBRD(134), + 150, COMBRD(150), + 200, COMBRD(200), + 300, COMBRD(300), + 600, COMBRD(600), + 1200, COMBRD(1200), + 1800, COMBRD(1800), + 2400, COMBRD(2400), + 4800, COMBRD(4800), + 9600, COMBRD(9600), + 19200, COMBRD(19200), + 38400, COMBRD(38400), + 57600, COMBRD(57600), + 115200, COMBRD(115200), + -1, -1 +}; + +/* XXX - configure this list */ +static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, }; + +static int +sioprobe(dev) + struct isa_device *dev; +{ + static bool_t already_init; + Port_t *com_ptr; + Port_t iobase; + int result; + + if (!already_init) { + /* + * Turn off MCR_IENABLE for all likely serial ports. An unused + * port with its MCR_IENABLE gate open will inhibit interrupts + * from any used port that shares the interrupt vector. + */ + for (com_ptr = likely_com_ports; + com_ptr < &likely_com_ports[sizeof likely_com_ports + / sizeof likely_com_ports[0]]; + ++com_ptr) + outb(*com_ptr + com_mcr, 0); + already_init = TRUE; + } + iobase = dev->id_iobase; + result = 1; + + /* + * We don't want to get actual interrupts, just masked ones. + * Interrupts from this line should already be masked in the ICU, + * but mask them in the processor as well in case there are some + * (misconfigured) shared interrupts. + */ + disable_intr(); + + /* + * Enable output interrupts (only) and check the following: + * o the CFCR, IER and MCR in UART hold the values written to them + * (the values happen to be all distinct - this is good for + * avoiding false positive tests from bus echoes). + * o an output interrupt is generated and its vector is correct. + * o the interrupt goes away when the IIR in the UART is read. + */ + outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */ + outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */ + outb(iobase + com_ier, 0); /* ensure edge on next intr */ + outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */ + if ( inb(iobase + com_cfcr) != CFCR_8BITS + || inb(iobase + com_ier) != IER_ETXRDY + || inb(iobase + com_mcr) != MCR_IENABLE + || !isa_irq_pending(dev) + || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY + || isa_irq_pending(dev) + || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND) + result = 0; + + /* + * Turn off all device interrupts and check that they go off properly. + * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to + * the ICU input. Closing the gate would give a floating ICU input + * (unless there is another device driving at) and spurious interrupts. + * (On the system that this was first tested on, the input floats high + * and gives a (masked) interrupt as soon as the gate is closed.) + */ + outb(iobase + com_ier, 0); + outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */ + if ( inb(iobase + com_ier) != 0 + || isa_irq_pending(dev) + || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND) + result = 0; + + enable_intr(); + + return (result); +} + +static int /* XXX - should be void */ +sioattach(isdp) + struct isa_device *isdp; +{ + struct com_s *com; + static bool_t comwakeup_started = FALSE; + Port_t iobase; + int s; + u_char scr; + u_char scr1; + u_char scr2; + int unit; + + iobase = isdp->id_iobase; + unit = isdp->id_unit; + if (unit == comconsole) + DELAY(1000); /* XXX */ + s = spltty(); + + /* + * sioprobe() has initialized the device registers as follows: + * o cfcr = CFCR_8BITS. + * It is most important that CFCR_DLAB is off, so that the + * data port is not hidden when we enable interrupts. + * o ier = 0. + * Interrupts are only enabled when the line is open. + * o mcr = MCR_IENABLE. + * Keeping MCR_DTR and MCR_RTS off might stop the external + * device from sending before we are ready. + */ + + com = &com_structs[unit]; + com->cfcr_image = CFCR_8BITS; + com->mcr_image = MCR_IENABLE; +#if 0 + com->softDCD = TRUE; +#endif + com->iptr = com->ibuf = com->ibuf1; + com->ibufend = com->ibuf1 + RS_IBUFSIZE; + com->ihighwater = com->ibuf1 + RS_IHIGHWATER; + com->iobase = iobase; + com->data_port = iobase + com_data; + com->int_id_port = iobase + com_iir; + com->modem_ctl_port = iobase + com_mcr; + com->line_status_port = iobase + com_lsr; + com->modem_status_port = iobase + com_msr; + com->tp = &sio_tty[unit]; +#ifdef COM_BIDIR + /* + * if bidirectional ports possible, clear the bidir port info; + */ + com->bidir = FALSE; + com->active = FALSE; + com->active_in = com->active_out = FALSE; +#endif /* COM_BIDIR */ + + /* attempt to determine UART type */ + scr = inb(iobase + com_scr); + outb(iobase + com_scr, 0xa5); + scr1 = inb(iobase + com_scr); + outb(iobase + com_scr, 0x5a); + scr2 = inb(iobase + com_scr); + outb(iobase + com_scr, scr); + if (scr1 != 0xa5 || scr2 != 0x5a) + printf(" <8250>"); + else { + outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14); + DELAY(100); + switch (inb(iobase + com_iir) & IIR_FIFO_MASK) { + case FIFO_TRIGGER_1: + printf(" <16450>"); + break; + case FIFO_TRIGGER_4: + printf(" <16450?>"); + break; + case FIFO_TRIGGER_8: + printf(" <16550?>"); + break; + case FIFO_TRIGGER_14: + com->hasfifo = TRUE; + printf(" <16550A>"); + break; + } + outb(iobase + com_fifo, 0); + } +#ifdef COM_MULTIPORT + if (COM_ISMULTIPORT(isdp)) { + struct isa_device *masterdev; + + com->multiport = TRUE; + printf(" (multiport)"); + + /* set the master's common-interrupt-enable reg., + * as appropriate. YYY See your manual + */ + /* enable only common interrupt for port */ + outb(iobase + com_mcr, 0); + + masterdev = find_isadev(isa_devtab_tty, &siodriver, + COM_MPMASTER(isdp)); + outb(masterdev->id_iobase+com_scr, 0x80); + } + else + com->multiport = FALSE; +#endif /* COM_MULTIPORT */ + +#ifdef KGDB + if (kgdb_dev == makedev(commajor, unit)) { + if (comconsole == unit) + kgdb_dev = -1; /* can't debug over console port */ + else { + cominit(unit, kgdb_rate); + if (kgdb_debug_init) { + /* + * Print prefix of device name, + * let kgdb_connect print the rest. + */ + printf("com%d: ", unit); + kgdb_connect(1); + } + else + printf("com%d: kgdb enabled\n", unit); + } + } +#endif + + /* + * Need to reset baud rate, etc. of next print so reset comconsinit. + * Also make sure console is always "hardwired" + */ + if (unit == comconsole) { + comconsinit = FALSE; + com->softDCD = TRUE; + } + + com_addr(unit) = com; + + splx(s); + + if (!comwakeup_started) { + comwakeup(); + comwakeup_started = TRUE; + } + + return (1); +} + +/* ARGSUSED */ +int +sioopen(dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + struct com_s *com; + int error = 0; + Port_t iobase; + int s; + struct tty *tp; + int unit = UNIT(dev); +#ifdef COM_BIDIR + bool_t callout = CALLOUT(dev); +#endif /* COM_BIDIR */ + if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL) + return (ENXIO); +#ifdef COM_BIDIR + /* if it's a callout device, and bidir not possible on that dev, die */ + if (callout && !(com->bidir)) + return (ENXIO); +#endif /* COM_BIDIR */ + + tp = com->tp; + s = spltty(); + +#ifdef COM_BIDIR + +bidir_open_top: + /* if it's bidirectional, we've gotta deal with it... */ + if (com->bidir) { + if (callout) { + if (com->active_in) { + /* it's busy. die */ + splx(s); + return (EBUSY); + } else { + /* it's ours. lock it down, and set it up */ + com->active_out = TRUE; + com->softDCD = TRUE; + } + } else { + if (com->active_out) { + /* it's busy, outgoing. wait, if possible */ + if (flag & O_NONBLOCK) { + /* can't wait; bail */ + splx(s); + return (EBUSY); + } else { + /* wait for it... */ + error = tsleep(&com->active_out, + TTIPRI|PCATCH, + "comoth", + 0); + /* if there was an error, take off. */ + if (error != 0) { + splx(s); + return (error); + } + /* else take it from the top */ + goto bidir_open_top; + } + } else if (com->last_modem_status & MSR_DCD) { + /* there's a carrier on the line; we win */ + com->active_in = TRUE; + com->softDCD = FALSE; + } else { + /* there is no carrier on the line */ + if (flag & O_NONBLOCK) { + /* can't wait; let it open */ + com->active_in = TRUE; + com->softDCD = FALSE; + } else { + /* put DTR & RTS up */ + /* NOTE: cgd'sdriver used the ier register + * to enable/disable interrupts. This one + * uses both ier and IENABLE in the mcr. + */ + (void) commctl(com, MCR_DTR | MCR_RTS, DMSET); + outb(com->iobase + com_ier, IER_EMSC); + /* wait for it... */ + error = tsleep(&com->active_in, + TTIPRI|PCATCH, + "comdcd", + 0); + + /* if not active, turn DTR & RTS off */ + if (!com->active) + (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC); + + /* if there was an error, take off. */ + if (error != 0) { + splx(s); + return (error); + } + /* else take it from the top */ + goto bidir_open_top; + } + } + } + } + + com->active = TRUE; +#endif /* COM_BIDIR */ + + tp->t_oproc = comstart; + tp->t_param = comparam; + tp->t_dev = dev; + if (!(tp->t_state & TS_ISOPEN)) { + tp->t_state |= TS_WOPEN; + ttychars(tp); + if (tp->t_ispeed == 0) { + /* + * We no longer use the flags from <sys/ttydefaults.h> + * since those are only relevant for logins. It's + * important to have echo off initially so that the + * line doesn't start blathering before the echo flag + * can be turned off. It's useful to have clocal on + * initially so that "stty changed-defaults </dev/comx" + * doesn't hang waiting for carrier. + */ + tp->t_iflag = 0; + tp->t_oflag = 0; + tp->t_cflag = CREAD | CS8 | CLOCAL; + tp->t_lflag = 0; + tp->t_ispeed = tp->t_ospeed = comdefaultrate; + } + (void) commctl(com, MCR_DTR | MCR_RTS, DMSET); + error = comparam(tp, &tp->t_termios); + if (error != 0) + goto out; + ttsetwater(tp); + iobase = com->iobase; + disable_intr(); + if (com->hasfifo) + /* (re)enable and drain FIFO */ + outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14 + | FIFO_RCV_RST | FIFO_XMT_RST); + (void) inb(com->line_status_port); + (void) inb(com->data_port); + com->last_modem_status = + com->prev_modem_status = inb(com->modem_status_port); + outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS + | IER_EMSC); + enable_intr(); + if (com->softDCD || com->prev_modem_status & MSR_DCD) + tp->t_state |= TS_CARR_ON; + } + else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { + splx(s); + return (EBUSY); + } + while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) +#ifdef COM_BIDIR + /* We went through a lot of trouble to open it, + * but it's certain we have a carrier now, so + * don't spend any time on it now. + */ + && !(com->bidir) +#endif /* COM_BIDIR */ + && !(tp->t_state & TS_CARR_ON)) { + tp->t_state |= TS_WOPEN; + error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, + ttopen, 0); + if (error != 0) + break; + } +out: + splx(s); + if (error == 0) + error = (*linesw[tp->t_line].l_open)(dev, tp); + +#ifdef COM_BIDIR + /* wakeup sleepers */ + wakeup((caddr_t) &com->active_in); +#endif /* COM_BIDIR */ + + /* + * XXX - the next step was once not done, so interrupts, DTR and RTS + * remainded hot if the process was killed while it was sleeping + * waiting for carrier. Now there is the opposite problem. If several + * processes are sleeping waiting for carrier on the same line and one + * is killed, interrupts are turned off so the other processes will + * never see the carrier rise. + */ + if (error != 0 && !(tp->t_state & TS_ISOPEN)) +{ + comhardclose(com); +} + tp->t_state &= ~TS_WOPEN; + + return (error); +} + +/*ARGSUSED*/ +int +sioclose(dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + struct com_s *com; + struct tty *tp; + + com = com_addr(UNIT(dev)); + tp = com->tp; + (*linesw[tp->t_line].l_close)(tp, flag); + comhardclose(com); + ttyclose(tp); + return (0); +} + +void +comhardclose(com) + struct com_s *com; +{ + Port_t iobase; + int s; + struct tty *tp; + + s = spltty(); + iobase = com->iobase; + outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); +#ifdef KGDB + /* do not disable interrupts if debugging */ + if (kgdb_dev != makedev(commajor, com - &com_structs[0])) +#endif + outb(iobase + com_ier, 0); + tp = com->tp; + if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN + || !(tp->t_state & TS_ISOPEN)) + (void) commctl(com, 0, DMSET); +#ifdef COM_BIDIR + com->active = com->active_in = com->active_out = FALSE; + com->softDCD = FALSE; + + /* wakeup sleepers who are waiting for out to finish */ + wakeup((caddr_t) &com->active_out); +#endif /* COM_BIDIR */ + + splx(s); +} + +int +sioread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct tty *tp = com_addr(UNIT(dev))->tp; + + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +int +siowrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + int unit = UNIT(dev); + struct tty *tp = com_addr(unit)->tp; + + /* + * (XXX) We disallow virtual consoles if the physical console is + * a serial port. This is in case there is a display attached that + * is not the console. In that situation we don't need/want the X + * server taking over the console. + */ + if (constty && unit == comconsole) + constty = NULL; + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +void +siointr(unit) + int unit; +{ + struct com_s *com; +#ifndef COM_MULTIPORT + u_char line_status; + u_char modem_status; + u_char *ioptr; + u_char recv_data; + + com = com_addr(unit); +#else /* COM_MULTIPORT */ + int i; + bool_t donesomething; + + do { + donesomething = FALSE; + for(i=0;i<NSIO;i++) { + com=com_addr(i); + if(com != NULL) { + /* XXX When siointr is called + * to start output, maybe + * it should be changed to a + * call to comintr1. Doesn't + * seem a good idea: interrupts + * are disabled all the time. + */ +enable_intr(); +disable_intr(); + donesomething = comintr1(com); + } + } + } while (donesomething); + return; +} + +bool_t +comintr1(struct com_s *com) +{ + u_char line_status; + u_char modem_status; + u_char *ioptr; + u_char recv_data; + bool_t donesomething; + + donesomething = FALSE; +#endif /* COM_MULTIPORT */ + + while (TRUE) { + line_status = inb(com->line_status_port); + + /* input event? (check first to help avoid overruns) */ + while (line_status & LSR_RCV_MASK) { + /* break/unnattached error bits or real input? */ +#ifdef COM_MULTIPORT + donesomething = TRUE; +#endif /* COM_MULTIPORT */ + if (!(line_status & LSR_RXRDY)) + recv_data = 0; + else + recv_data = inb(com->data_port); + ++com->bytes_in; +#ifdef KGDB + /* trap into kgdb? (XXX - needs testing and optim) */ + if (recv_data == FRAME_END + && !(com->tp->t_state & TS_ISOPEN) + && kgdb_dev == makedev(commajor, unit)) { + kgdb_connect(0); + continue; + } +#endif /* KGDB */ + ioptr = com->iptr; + if (ioptr >= com->ibufend) + CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW); + else { + ++com_events; + ioptr[0] = recv_data; + ioptr[CE_INPUT_OFFSET] = line_status; + com->iptr = ++ioptr; + if (ioptr == com->ihighwater + && com->state & CS_RTS_IFLOW) + outb(com->modem_ctl_port, + com->mcr_image &= ~MCR_RTS); + } + + /* + * "& 0x7F" is to avoid the gcc-1.40 generating a slow + * jump from the top of the loop to here + */ + line_status = inb(com->line_status_port) & 0x7F; + } + + /* modem status change? (always check before doing output) */ + modem_status = inb(com->modem_status_port); + if (modem_status != com->last_modem_status) { + /* + * Schedule high level to handle DCD changes. Note + * that we don't use the delta bits anywhere. Some + * UARTs mess them up, and it's easy to remember the + * previous bits and calculate the delta. + */ +#ifdef COM_MULTIPORT + donesomething = TRUE; +#endif /* COM_MULTIPORT */ + com->last_modem_status = modem_status; + if (!(com->state & CS_CHECKMSR)) { + com_events += LOTS_OF_EVENTS; + com->state |= CS_CHECKMSR; + schedsoftcom(); + } + + /* handle CTS change immediately for crisp flow ctl */ + if (com->state & CS_CTS_OFLOW) { + if (modem_status & MSR_CTS) + com->state |= CS_ODEVREADY; + else + com->state &= ~CS_ODEVREADY; + } + } + + /* output queued and everything ready? */ + if (line_status & LSR_TXRDY + && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) { +#ifdef COM_MULTIPORT + donesomething = TRUE; +#endif /* COM_MULTIPORT */ + ioptr = com->optr; + outb(com->data_port, *ioptr); + ++com->bytes_out; + com->optr = ++ioptr; + if (ioptr >= com->obufend) { + /* output just completed */ + com_events += LOTS_OF_EVENTS; + com->state ^= (CS_ODONE | CS_BUSY); + schedsoftcom(); /* handle at high level ASAP */ + } + } + + /* finished? */ + if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND) +#ifdef COM_MULTIPORT + return (donesomething); +#else + return; +#endif /* COM_MULTIPORT */ + } +} + +int +sioioctl(dev, cmd, data, flag, p) + dev_t dev; + int cmd; + caddr_t data; + int flag; + struct proc *p; +{ + struct com_s *com; + int error; + Port_t iobase; + int s; + struct tty *tp; + + com = com_addr(UNIT(dev)); + tp = com->tp; + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); + if (error >= 0) + return (error); + error = ttioctl(tp, cmd, data, flag); + if (error >= 0) + return (error); + + iobase = com->iobase; + s = spltty(); + switch (cmd) { + case TIOCSBRK: + outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK); + break; + case TIOCCBRK: + outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); + break; + case TIOCSDTR: + (void) commctl(com, MCR_DTR | MCR_RTS, DMBIS); + break; + case TIOCCDTR: + (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC); + break; + case TIOCMSET: + (void) commctl(com, *(int *)data, DMSET); + break; + case TIOCMBIS: + (void) commctl(com, *(int *)data, DMBIS); + break; + case TIOCMBIC: + (void) commctl(com, *(int *)data, DMBIC); + break; + case TIOCMGET: + *(int *)data = commctl(com, 0, DMGET); + break; +#ifdef COM_BIDIR + case TIOCMSBIDIR: + /* must be root to set bidir. capability */ + if (p->p_ucred->cr_uid != 0) + return(EPERM); + + /* if it's the console, can't do it */ + if (UNIT(dev) == comconsole) + return(ENOTTY); + + /* can't do the next, for obvious reasons... + * but there are problems to be looked at... + */ + + /* if the port is active, don't do it */ + /* if (com->active) + return(EBUSY); */ + + com->bidir = *(int *)data; + break; + case TIOCMGBIDIR: + *(int *)data = com->bidir; + break; +#endif /* COM_BIDIR */ + default: + splx(s); + return (ENOTTY); + } + splx(s); + return (0); +} + +/* cancel pending output */ +static void +comflush(com) + struct com_s *com; +{ + struct ringb *rbp; + + disable_intr(); + if (com->state & CS_ODONE) + com_events -= LOTS_OF_EVENTS; + com->state &= ~(CS_ODONE | CS_BUSY); + enable_intr(); + rbp = &com->tp->t_out; + rbp->rb_hd += com->ocount; + rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd); + com->ocount = 0; + com->tp->t_state &= ~TS_BUSY; +} + +static void +compoll() +{ + static bool_t awake = FALSE; + struct com_s *com; + int s; + int unit; + + if (com_events == 0) + return; + disable_intr(); + if (awake) { + enable_intr(); + return; + } + awake = TRUE; + enable_intr(); + s = spltty(); +repeat: + for (unit = 0; unit < NSIO; ++unit) { + u_char *buf; + u_char *ibuf; + int incc; + struct tty *tp; + + com = com_addr(unit); + if (com == NULL) + continue; + tp = com->tp; + + /* switch the role of the low-level input buffers */ + if (com->iptr == (ibuf = com->ibuf)) + incc = 0; + else { + buf = ibuf; + disable_intr(); + incc = com->iptr - buf; + com_events -= incc; + if (ibuf == com->ibuf1) + ibuf = com->ibuf2; + else + ibuf = com->ibuf1; + com->ibufend = ibuf + RS_IBUFSIZE; + com->ihighwater = ibuf + RS_IHIGHWATER; + com->iptr = ibuf; + + /* + * There is now room for another low-level buffer full + * of input, so enable RTS if it is now disabled and + * there is room in the high-level buffer. + */ + if (!(com->mcr_image & MCR_RTS) + && !(tp->t_state & TS_RTSBLOCK)) + outb(com->modem_ctl_port, + com->mcr_image |= MCR_RTS); + enable_intr(); + com->ibuf = ibuf; + } + + if (com->state & CS_CHECKMSR) { + u_char delta_modem_status; + + disable_intr(); + delta_modem_status = com->last_modem_status + ^ com->prev_modem_status; + com->prev_modem_status = com->last_modem_status; + com_events -= LOTS_OF_EVENTS; + com->state &= ~CS_CHECKMSR; + enable_intr(); + if (delta_modem_status & MSR_DCD && + unit != comconsole) { +#ifdef COM_BIDIR + if (com->prev_modem_status & MSR_DCD) { + (*linesw[tp->t_line].l_modem)(tp, 1); + com->softDCD = FALSE; + wakeup((caddr_t) &com->active_in); + } +#else + if (com->prev_modem_status & MSR_DCD) + (*linesw[tp->t_line].l_modem)(tp, 1); +#endif /* COM_BIDIR */ + else if ((*linesw[tp->t_line].l_modem)(tp, 0) + == 0) { + disable_intr(); + outb(com->modem_ctl_port, + com->mcr_image + &= ~(MCR_DTR | MCR_RTS)); + enable_intr(); + } + } + } + + /* XXX */ + if (TRUE) { + u_int delta; + u_int delta_error_counts[CE_NTYPES]; + int errnum; + u_long total; + + disable_intr(); + bcopy(com->delta_error_counts, delta_error_counts, + sizeof delta_error_counts); + bzero(com->delta_error_counts, + sizeof delta_error_counts); + enable_intr(); + for (errnum = 0; errnum < CE_NTYPES; ++errnum) { + delta = delta_error_counts[errnum]; + if (delta != 0) { + total = + com->error_counts[errnum] += delta; + log(LOG_WARNING, + "com%d: %u more %s%s (total %lu)\n", + unit, delta, error_desc[errnum], + delta == 1 ? "" : "s", total); + } + } + } + if (com->state & CS_ODONE) { + comflush(com); + /* XXX - why isn't the table used for t_line == 0? */ + if (tp->t_line != 0) + (*linesw[tp->t_line].l_start)(tp); + else + comstart(tp); + } + if (incc <= 0 || !(tp->t_state & TS_ISOPEN)) + continue; + if (com->state & CS_RTS_IFLOW + && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER + && !(tp->t_state & TS_RTSBLOCK) + /* + * XXX - need RTS flow control for all line disciplines. + * Only have it in standard one now. + */ + && linesw[tp->t_line].l_rint == ttyinput) { + tp->t_state |= TS_RTSBLOCK; + ttstart(tp); + } + /* + * Avoid the grotesquely inefficient lineswitch routine + * (ttyinput) in "raw" mode. It usually takes about 450 + * instructions (that's without canonical processing or echo!). + * slinput is reasonably fast (usually 40 instructions plus + * call overhead). + */ + if (!(tp->t_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP + | IXOFF | IXON)) + && !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG + | PENDIN)) + && !(tp->t_state & (TS_CNTTB | TS_LNCH)) + && linesw[tp->t_line].l_rint == ttyinput) { + tk_nin += incc; + tk_rawcc += incc; + tp->t_rawcc += incc; + com->delta_error_counts[CE_TTY_BUF_OVERFLOW] + += incc - rb_write(&tp->t_raw, (char *) buf, + incc); + ttwakeup(tp); + if (tp->t_state & TS_TTSTOP + && (tp->t_iflag & IXANY + || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { + tp->t_state &= ~TS_TTSTOP; + tp->t_lflag &= ~FLUSHO; + ttstart(tp); + } + } + else { + do { + u_char line_status; + int recv_data; + + line_status = (u_char) buf[CE_INPUT_OFFSET]; + recv_data = (u_char) *buf++; + if (line_status + & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) { + if (line_status & LSR_BI) + recv_data |= TTY_BI; + if (line_status & LSR_FE) + recv_data |= TTY_FE; + if (line_status & LSR_OE) + recv_data |= TTY_OE; + if (line_status & LSR_PE) + recv_data |= TTY_PE; + } + (*linesw[tp->t_line].l_rint)(recv_data, tp); + } while (--incc > 0); + } + if (com_events == 0) + break; + } + if (com_events >= LOTS_OF_EVENTS) + goto repeat; + splx(s); + awake = FALSE; +} + +static int +comparam(tp, t) + struct tty *tp; + struct termios *t; +{ + u_int cfcr; + int cflag; + struct com_s *com; + int divisor; + int error; + Port_t iobase; + int s; + int unit; + + /* check requested parameters */ + divisor = ttspeedtab(t->c_ospeed, comspeedtab); + if (divisor < 0 || t->c_ispeed != 0 && t->c_ispeed != t->c_ospeed) + return (EINVAL); + + /* parameters are OK, convert them to the com struct and the device */ + unit = UNIT(tp->t_dev); + com = com_addr(unit); + iobase = com->iobase; + s = spltty(); + if (divisor == 0) { + (void) commctl(com, 0, DMSET); /* hang up line */ + splx(s); + return (0); + } + cflag = t->c_cflag; + switch (cflag & CSIZE) { + case CS5: + cfcr = CFCR_5BITS; + break; + case CS6: + cfcr = CFCR_6BITS; + break; + case CS7: + cfcr = CFCR_7BITS; + break; + default: + cfcr = CFCR_8BITS; + break; + } + if (cflag & PARENB) { + cfcr |= CFCR_PENAB; + if (!(cflag & PARODD)) + cfcr |= CFCR_PEVEN; + } + if (cflag & CSTOPB) + cfcr |= CFCR_STOPB; + + /* + * Some UARTs lock up if the divisor latch registers are selected + * while the UART is doing output (they refuse to transmit anything + * more until given a hard reset). Fix this by stopping filling + * the device buffers and waiting for them to drain. Reading the + * line status port outside of siointr() might lose some receiver + * error bits, but that is acceptable here. + */ + disable_intr(); + com->state &= ~CS_TTGO; + enable_intr(); + while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) + != (LSR_TSRE | LSR_TXRDY)) { + error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, + "comparam", 1); + if (error != 0 && error != EAGAIN) { + if (!(tp->t_state & TS_TTSTOP)) { + disable_intr(); + com->state |= CS_TTGO; + enable_intr(); + } + splx(s); + return (error); + } + } + + disable_intr(); /* very important while com_data is hidden */ + outb(iobase + com_cfcr, cfcr | CFCR_DLAB); + outb(iobase + com_dlbl, divisor & 0xFF); + outb(iobase + com_dlbh, (u_int) divisor >> 8); + outb(iobase + com_cfcr, com->cfcr_image = cfcr); + if (!(tp->t_state & TS_TTSTOP)) + com->state |= CS_TTGO; + if (cflag & CRTS_IFLOW) + com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */ + else + com->state &= ~CS_RTS_IFLOW; + + /* + * Set up state to handle output flow control. + * XXX - worth handling MDMBUF (DCD) flow control at the lowest level? + * Now has 16+ msec latency, while CTS flow has 50- usec latency. + * Note that DCD flow control stupidly uses the same state flag + * (TS_TTSTOP) as XON/XOFF flow control. + */ + com->state &= ~CS_CTS_OFLOW; + com->state |= CS_ODEVREADY; + if (cflag & CCTS_OFLOW) { + com->state |= CS_CTS_OFLOW; + if (!(com->prev_modem_status & MSR_CTS)) + com->state &= ~CS_ODEVREADY; + } + + enable_intr(); + siointr(unit); /* recover from fiddling with CS_TTGO */ + splx(s); + return (0); +} + +static int /* XXX - should be void */ +comstart(tp) + struct tty *tp; +{ + struct com_s *com; + int s; + int unit; + + unit = UNIT(tp->t_dev); + com = com_addr(unit); + s = spltty(); + disable_intr(); + if (tp->t_state & TS_TTSTOP) + com->state &= ~CS_TTGO; + else + com->state |= CS_TTGO; + if (tp->t_state & TS_RTSBLOCK) { + if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW) + outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); + } + else { + if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater) + outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); + } + enable_intr(); + if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) + goto out; + if (RB_LEN(&tp->t_out) <= tp->t_lowat) { + if (tp->t_state & TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t)&tp->t_out); + } + if (tp->t_wsel) { + selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); + tp->t_wsel = 0; + tp->t_state &= ~TS_WCOLL; + } + } + if (com->ocount != 0) { + disable_intr(); + siointr(unit); + enable_intr(); + } + else if (RB_LEN(&tp->t_out) != 0) { + tp->t_state |= TS_BUSY; + com->ocount = RB_CONTIGGET(&tp->t_out); + disable_intr(); + com->obufend = (com->optr = (u_char *) tp->t_out.rb_hd) + + com->ocount; + com->state |= CS_BUSY; + siointr(unit); /* fake interrupt to start output */ + enable_intr(); + } +out: + splx(s); + return (1); +} + +void +siostop(tp, rw) + struct tty *tp; + int rw; +{ + struct com_s *com; + + com = com_addr(UNIT(tp->t_dev)); + if (rw & FWRITE) + comflush(com); + disable_intr(); + if (tp->t_state & TS_TTSTOP) + com->state &= ~CS_TTGO; + else + com->state |= CS_TTGO; + enable_intr(); +} + +static int +commctl(com, bits, how) + struct com_s *com; + int bits; + int how; +{ + disable_intr(); + switch (how) { + case DMSET: +#ifdef COM_MULTIPORT + /* YYY maybe your card doesn't want IENABLE to be reset? */ + if(com->multiport) + outb(com->modem_ctl_port, + com->mcr_image = bits); + else +#endif /* COM_MULTIPORT */ + outb(com->modem_ctl_port, + com->mcr_image = bits | MCR_IENABLE); + break; + case DMBIS: + outb(com->modem_ctl_port, com->mcr_image |= bits); + break; + case DMBIC: +#ifdef COM_MULTIPORT + /* YYY maybe your card doesn't want IENABLE to be reset? */ + if(com->multiport) + outb(com->modem_ctl_port, + com->mcr_image &= ~(bits)); + else +#endif /* COM_MULTIPORT */ + outb(com->modem_ctl_port, + com->mcr_image &= ~(bits & ~MCR_IENABLE)); + break; + case DMGET: + bits = com->prev_modem_status; + break; + } + enable_intr(); + return (bits); +} + +static void +comwakeup() +{ + struct com_s *com; + int unit; + + timeout((timeout_func_t) comwakeup, (caddr_t) NULL, 1); + if (com_events != 0) + /* schedule compoll() to run when the cpl allows */ + schedsoftcom(); + + /* recover from lost output interrupts */ + for (unit = 0; unit < NSIO; ++unit) { + com = com_addr(unit); + if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) { + disable_intr(); + siointr(unit); + enable_intr(); + } + } +} + +void +softsio0() { compoll(); } + +void +softsio1() { compoll(); } + +void +softsio2() { compoll(); } + +void +softsio3() { compoll(); } + +void +softsio4() { compoll(); } + +void +softsio5() { compoll(); } + +void +softsio6() { compoll(); } + +void +softsio7() { compoll(); } + +void +softsio8() { compoll(); } + +/* + * Following are all routines needed for COM to act as console + * XXX - not tested in this version + * XXX - check that the corresponding serial interrupts are never enabled + */ +#include "i386/i386/cons.h" + +void +siocnprobe(cp) + struct consdev *cp; +{ + int unit; + + /* locate the major number */ + for (commajor = 0; commajor < nchrdev; commajor++) + if (cdevsw[commajor].d_open == (bogus_open_t) sioopen) + break; + + /* XXX: ick */ + unit = CONUNIT; + com_addr(unit) = &com_structs[unit]; + com_addr(unit)->iobase = CONADDR; + + /* make sure hardware exists? XXX */ + + /* initialize required fields */ + cp->cn_dev = makedev(commajor, unit); + cp->cn_tp = &sio_tty[unit]; +#ifdef COMCONSOLE + cp->cn_pri = CN_REMOTE; /* Force a serial port console */ +#else + cp->cn_pri = CN_NORMAL; +#endif +} + +void +siocninit(cp) + struct consdev *cp; +{ + int unit; + + unit = UNIT(cp->cn_dev); + cominit(unit, comdefaultrate); + comconsole = unit; + comconsinit = TRUE; +} + +static void +cominit(unit, rate) + int unit; + int rate; +{ + Port_t iobase; + int s; + + iobase = com_addr(unit)->iobase; + s = splhigh(); + outb(iobase + com_cfcr, CFCR_DLAB); + rate = ttspeedtab(comdefaultrate, comspeedtab); + outb(iobase + com_data, rate & 0xFF); + outb(iobase + com_ier, rate >> 8); + outb(iobase + com_cfcr, CFCR_8BITS); + + /* + * XXX - fishy to enable interrupts and then poll. + * It shouldn't be necessary to ready the iir. + */ + outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); + outb(iobase + com_fifo, + FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); + (void) inb(iobase + com_iir); + splx(s); +} + +int +siocngetc(dev) + dev_t dev; +{ + int c; + Port_t iobase; + int s; + + iobase = com_addr(UNIT(dev))->iobase; + s = splhigh(); + while (!(inb(iobase + com_lsr) & LSR_RXRDY)) + ; + c = inb(iobase + com_data); + (void) inb(iobase + com_iir); + splx(s); + return (c); +} + +void +siocnputc(dev, c) + dev_t dev; + int c; +{ + Port_t iobase; + int s; + int timo; + + iobase = com_addr(UNIT(dev))->iobase; + s = splhigh(); +#ifdef KGDB + if (dev != kgdb_dev) +#endif + if (!comconsinit) { + (void) cominit(UNIT(dev), comdefaultrate); + comconsinit = TRUE; + } + /* wait for any pending transmission to finish */ + timo = 50000; + while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo) + ; + outb(iobase + com_data, c); + /* wait for this transmission to complete */ + timo = 1500000; + while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo) + ; + /* clear any interrupts generated by this transmission */ + (void) inb(iobase + com_iir); + splx(s); +} + +/* + * 10 Feb 93 Jordan K. Hubbard Added select code + * 27 May 93 Rodney W. Grimes Stole the select code from com.c.pl5 + */ + +int +sioselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; +{ + register struct tty *tp = &sio_tty[UNIT(dev)]; + int nread; + int s = spltty(); + struct proc *selp; + + switch (rw) { + + case FREAD: + nread = ttnread(tp); + if (nread > 0 || + ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) + goto win; + if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_RCOLL; + else + tp->t_rsel = p->p_pid; + break; + + case FWRITE: + if (RB_LEN(&tp->t_out) <= tp->t_lowat) + goto win; + if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_WCOLL; + else + tp->t_wsel = p->p_pid; + break; + } + splx(s); + return (0); + win: + splx(s); + return (1); +} + +#endif /* NSIO > 0 */ diff --git a/sys/dev/sio/sioreg.h b/sys/dev/sio/sioreg.h new file mode 100644 index 000000000000..2a626832e87c --- /dev/null +++ b/sys/dev/sio/sioreg.h @@ -0,0 +1,113 @@ +/*- + * 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. + * + * @(#)comreg.h 7.2 (Berkeley) 5/9/91 + */ + + +/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */ +#define COMBRD(x) (1843200 / (16*(x))) + +/* interrupt enable register */ +#define IER_ERXRDY 0x1 +#define IER_ETXRDY 0x2 +#define IER_ERLS 0x4 +#define IER_EMSC 0x8 + +/* interrupt identification register */ +#define IIR_IMASK 0xf +#define IIR_RXTOUT 0xc +#define IIR_RLS 0x6 +#define IIR_RXRDY 0x4 +#define IIR_TXRDY 0x2 +#define IIR_NOPEND 0x1 +#define IIR_MLSC 0x0 +#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */ + +/* fifo control register */ +#define FIFO_ENABLE 0x01 +#define FIFO_RCV_RST 0x02 +#define FIFO_XMT_RST 0x04 +#define FIFO_DMA_MODE 0x08 +#define FIFO_TRIGGER_1 0x00 +#define FIFO_TRIGGER_4 0x40 +#define FIFO_TRIGGER_8 0x80 +#define FIFO_TRIGGER_14 0xc0 + +/* character format control register */ +#define CFCR_DLAB 0x80 +#define CFCR_SBREAK 0x40 +#define CFCR_PZERO 0x30 +#define CFCR_PONE 0x20 +#define CFCR_PEVEN 0x10 +#define CFCR_PODD 0x00 +#define CFCR_PENAB 0x08 +#define CFCR_STOPB 0x04 +#define CFCR_8BITS 0x03 +#define CFCR_7BITS 0x02 +#define CFCR_6BITS 0x01 +#define CFCR_5BITS 0x00 + +/* modem control register */ +#define MCR_LOOPBACK 0x10 +#define MCR_IENABLE 0x08 +#define MCR_DRS 0x04 +#define MCR_RTS 0x02 +#define MCR_DTR 0x01 + +/* line status register */ +#define LSR_RCV_FIFO 0x80 +#define LSR_TSRE 0x40 +#define LSR_TXRDY 0x20 +#define LSR_BI 0x10 +#define LSR_FE 0x08 +#define LSR_PE 0x04 +#define LSR_OE 0x02 +#define LSR_RXRDY 0x01 +#define LSR_RCV_MASK 0x1f + +/* modem status register */ +#define MSR_DCD 0x80 +#define MSR_RI 0x40 +#define MSR_DSR 0x20 +#define MSR_CTS 0x10 +#define MSR_DDCD 0x08 +#define MSR_TERI 0x04 +#define MSR_DDSR 0x02 +#define MSR_DCTS 0x01 + +/* + * WARNING: Serial console is assumed to be at COM1 address + * and CONUNIT must be 0. + */ +#define CONADDR (0x3f8) +#define CONUNIT (0) diff --git a/sys/dev/speaker/spkr.c b/sys/dev/speaker/spkr.c new file mode 100644 index 000000000000..ffeec08fe5dd --- /dev/null +++ b/sys/dev/speaker/spkr.c @@ -0,0 +1,520 @@ +/* + * spkr.c -- device driver for console speaker on 80386 + * + * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 + * modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su> + * 386bsd only clean version, all SYSV stuff removed + * use hz value from param.c + */ + +#include "speaker.h" + +#if NSPEAKER > 0 + +#include "param.h" +#include "kernel.h" +#include "errno.h" +#include "buf.h" +#include "uio.h" +#include "spkr.h" + +/**************** MACHINE DEPENDENT PART STARTS HERE ************************* + * + * This section defines a function tone() which causes a tone of given + * frequency and duration from the 80x86's console speaker. + * Another function endtone() is defined to force sound off, and there is + * also a rest() entry point to do pauses. + * + * Audible sound is generated using the Programmable Interval Timer (PIT) and + * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The + * PPI controls whether sound is passed through at all; the PIT's channel 2 is + * used to generate clicks (a square wave) of whatever frequency is desired. + */ + +/* + * PIT and PPI port addresses and control values + * + * Most of the magic is hidden in the TIMER_PREP value, which selects PIT + * channel 2, frequency LSB first, square-wave mode and binary encoding. + * The encoding is as follows: + * + * +----------+----------+---------------+-----+ + * | 1 0 | 1 1 | 0 1 1 | 0 | + * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD | + * +----------+----------+---------------+-----+ + * Counter Write Mode 3 Binary + * Channel 2 LSB first, (Square Wave) Encoding + * MSB second + */ +#define PPI 0x61 /* port of Programmable Peripheral Interface */ +#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ +#define PIT_CTRL 0x43 /* PIT control address */ +#define PIT_COUNT 0x42 /* PIT count address */ +#define PIT_MODE 0xB6 /* set timer mode for sound generation */ + +/* + * Magic numbers for timer control. + */ +#define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */ + +static int endtone() +/* turn off the speaker, ending current tone */ +{ + wakeup((caddr_t)endtone); + outb(PPI, inb(PPI) & ~PPI_SPKR); +} + +static void tone(hz, ticks) +/* emit tone of frequency hz for given number of ticks */ +unsigned int hz, ticks; +{ + unsigned int divisor = TIMER_CLK / hz; + int sps; + +#ifdef DEBUG + printf("tone: hz=%d ticks=%d\n", hz, ticks); +#endif /* DEBUG */ + + /* set timer to generate clicks at given frequency in Hertz */ + sps = spltty(); + outb(PIT_CTRL, PIT_MODE); /* prepare timer */ + outb(PIT_COUNT, (unsigned char) divisor); /* send lo byte */ + outb(PIT_COUNT, (divisor >> 8)); /* send hi byte */ + splx(sps); + + /* turn the speaker on */ + outb(PPI, inb(PPI) | PPI_SPKR); + + /* + * Set timeout to endtone function, then give up the timeslice. + * This is so other processes can execute while the tone is being + * emitted. + */ + timeout((caddr_t)endtone, (caddr_t)NULL, ticks); + sleep((caddr_t)endtone, PZERO - 1); +} + +static int endrest() +/* end a rest */ +{ + wakeup((caddr_t)endrest); +} + +static void rest(ticks) +/* rest for given number of ticks */ +int ticks; +{ + /* + * Set timeout to endrest function, then give up the timeslice. + * This is so other processes can execute while the rest is being + * waited out. + */ +#ifdef DEBUG + printf("rest: %d\n", ticks); +#endif /* DEBUG */ + timeout((caddr_t)endrest, (caddr_t)NULL, ticks); + sleep((caddr_t)endrest, PZERO - 1); +} + +/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** + * + * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; + * M[LNS] are missing and the ~ synonym and octave-tracking facility is added. + * Requires tone(), rest(), and endtone(). String play is not interruptible + * except possibly at physical block boundaries. + */ + +typedef int bool; +#define TRUE 1 +#define FALSE 0 + +#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) +#define isdigit(c) (((c) >= '0') && ((c) <= '9')) +#define dtoi(c) ((c) - '0') + +static int octave; /* currently selected octave */ +static int whole; /* whole-note time at current tempo, in ticks */ +static int value; /* whole divisor for note time, quarter note = 1 */ +static int fill; /* controls spacing of notes */ +static bool octtrack; /* octave-tracking on? */ +static bool octprefix; /* override current octave-tracking state? */ + +/* + * Magic number avoidance... + */ +#define SECS_PER_MIN 60 /* seconds per minute */ +#define WHOLE_NOTE 4 /* quarter notes per whole note */ +#define MIN_VALUE 64 /* the most we can divide a note by */ +#define DFLT_VALUE 4 /* default value (quarter-note) */ +#define FILLTIME 8 /* for articulation, break note in parts */ +#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ +#define NORMAL 7 /* 7/8ths of note interval is filled */ +#define LEGATO 8 /* all of note interval is filled */ +#define DFLT_OCTAVE 4 /* default octave */ +#define MIN_TEMPO 32 /* minimum tempo */ +#define DFLT_TEMPO 120 /* default tempo */ +#define MAX_TEMPO 255 /* max tempo */ +#define NUM_MULT 3 /* numerator of dot multiplier */ +#define DENOM_MULT 2 /* denominator of dot multiplier */ + +/* letter to half-tone: A B C D E F G */ +static int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; + +/* + * This is the American Standard A440 Equal-Tempered scale with frequencies + * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... + * our octave 0 is standard octave 2. + */ +#define OCTAVE_NOTES 12 /* semitones per octave */ +static int pitchtab[] = +{ +/* C C# D D# E F F# G G# A A# B*/ +/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, +/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, +/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, +/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, +/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, +/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, +/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, +}; + +static void playinit() +{ + octave = DFLT_OCTAVE; + whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; + fill = NORMAL; + value = DFLT_VALUE; + octtrack = FALSE; + octprefix = TRUE; /* act as though there was an initial O(n) */ +} + +static void playtone(pitch, value, sustain) +/* play tone of proper duration for current rhythm signature */ +int pitch, value, sustain; +{ + register int sound, silence, snum = 1, sdenom = 1; + + /* this weirdness avoids floating-point arithmetic */ + for (; sustain; sustain--) + { + snum *= NUM_MULT; + sdenom *= DENOM_MULT; + } + + if (pitch == -1) + rest(whole * snum / (value * sdenom)); + else + { + sound = (whole * snum) / (value * sdenom) + - (whole * (FILLTIME - fill)) / (value * FILLTIME); + silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); + +#ifdef DEBUG + printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", + pitch, sound, silence); +#endif /* DEBUG */ + + tone(pitchtab[pitch], sound); + if (fill != LEGATO) + rest(silence); + } +} + +static int abs(n) +int n; +{ + if (n < 0) + return(-n); + else + return(n); +} + +static void playstring(cp, slen) +/* interpret and play an item from a notation string */ +char *cp; +size_t slen; +{ + int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; + +#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ + {v = v * 10 + (*++cp - '0'); slen--;} + for (; slen--; cp++) + { + int sustain, timeval, tempo; + register char c = toupper(*cp); + +#ifdef DEBUG + printf("playstring: %c (%x)\n", c, c); +#endif /* DEBUG */ + + switch (c) + { + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': + + /* compute pitch */ + pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; + + /* this may be followed by an accidental sign */ + if (cp[1] == '#' || cp[1] == '+') + { + ++pitch; + ++cp; + slen--; + } + else if (cp[1] == '-') + { + --pitch; + ++cp; + slen--; + } + + /* + * If octave-tracking mode is on, and there has been no octave- + * setting prefix, find the version of the current letter note + * closest to the last regardless of octave. + */ + if (octtrack && !octprefix) + { + if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) + { + ++octave; + pitch += OCTAVE_NOTES; + } + + if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) + { + --octave; + pitch -= OCTAVE_NOTES; + } + } + octprefix = FALSE; + lastpitch = pitch; + + /* ...which may in turn be followed by an override time value */ + GETNUM(cp, timeval); + if (timeval <= 0 || timeval > MIN_VALUE) + timeval = value; + + /* ...and/or sustain dots */ + for (sustain = 0; cp[1] == '.'; cp++) + { + slen--; + sustain++; + } + + /* time to emit the actual tone */ + playtone(pitch, timeval, sustain); + break; + + case 'O': + if (cp[1] == 'N' || cp[1] == 'n') + { + octprefix = octtrack = FALSE; + ++cp; + slen--; + } + else if (cp[1] == 'L' || cp[1] == 'l') + { + octtrack = TRUE; + ++cp; + slen--; + } + else + { + GETNUM(cp, octave); + if (octave >= sizeof(pitchtab) / OCTAVE_NOTES) + octave = DFLT_OCTAVE; + octprefix = TRUE; + } + break; + + case '>': + if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1) + octave++; + octprefix = TRUE; + break; + + case '<': + if (octave > 0) + octave--; + octprefix = TRUE; + break; + + case 'N': + GETNUM(cp, pitch); + for (sustain = 0; cp[1] == '.'; cp++) + { + slen--; + sustain++; + } + playtone(pitch - 1, value, sustain); + break; + + case 'L': + GETNUM(cp, value); + if (value <= 0 || value > MIN_VALUE) + value = DFLT_VALUE; + break; + + case 'P': + case '~': + /* this may be followed by an override time value */ + GETNUM(cp, timeval); + if (timeval <= 0 || timeval > MIN_VALUE) + timeval = value; + for (sustain = 0; cp[1] == '.'; cp++) + { + slen--; + sustain++; + } + playtone(-1, timeval, sustain); + break; + + case 'T': + GETNUM(cp, tempo); + if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) + tempo = DFLT_TEMPO; + whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo; + break; + + case 'M': + if (cp[1] == 'N' || cp[1] == 'n') + { + fill = NORMAL; + ++cp; + slen--; + } + else if (cp[1] == 'L' || cp[1] == 'l') + { + fill = LEGATO; + ++cp; + slen--; + } + else if (cp[1] == 'S' || cp[1] == 's') + { + fill = STACCATO; + ++cp; + slen--; + } + break; + } + } +} + +/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** + * + * This section implements driver hooks to run playstring() and the tone(), + * endtone(), and rest() functions defined above. + */ + +static int spkr_active; /* exclusion flag */ +static struct buf *spkr_inbuf; /* incoming buf */ + +int spkropen(dev) +dev_t dev; +{ +#ifdef DEBUG + printf("spkropen: entering with dev = %x\n", dev); +#endif /* DEBUG */ + + if (minor(dev) != 0) + return(ENXIO); + else if (spkr_active) + return(EBUSY); + else + { + playinit(); + spkr_inbuf = geteblk(DEV_BSIZE); + spkr_active = 1; + } + return(0); +} + +int spkrwrite(dev, uio) +dev_t dev; +struct uio *uio; +{ + register unsigned n; + char *cp; + int error; +#ifdef DEBUG + printf("spkrwrite: entering with dev = %x, count = %d\n", + dev, uio->uio_resid); +#endif /* DEBUG */ + + if (minor(dev) != 0) + return(ENXIO); + else + { + n = MIN(DEV_BSIZE, uio->uio_resid); + cp = spkr_inbuf->b_un.b_addr; + error = uiomove(cp, n, uio); + if (!error) + playstring(cp, n); + return(error); + } +} + +int spkrclose(dev) +dev_t dev; +{ +#ifdef DEBUG + printf("spkrclose: entering with dev = %x\n", dev); +#endif /* DEBUG */ + + if (minor(dev) != 0) + return(ENXIO); + else + { + endtone(); + brelse(spkr_inbuf); + spkr_active = 0; + } + return(0); +} + +int spkrioctl(dev, cmd, cmdarg) +dev_t dev; +int cmd; +caddr_t cmdarg; +{ +#ifdef DEBUG + printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd); +#endif /* DEBUG */ + + if (minor(dev) != 0) + return(ENXIO); + else if (cmd == SPKRTONE) + { + tone_t *tp = (tone_t *)cmdarg; + + if (tp->frequency == 0) + rest(tp->duration); + else + tone(tp->frequency, tp->duration); + } + else if (cmd == SPKRTUNE) + { + tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); + tone_t ttp; + int error; + + for (; ; tp++) { + error = copyin(tp, &ttp, sizeof(tone_t)); + if (error) + return(error); + if (ttp.duration == 0) + break; + if (ttp.frequency == 0) + rest(ttp.duration); + else + tone(ttp.frequency, ttp.duration); + } + } + else + return(EINVAL); + return(0); +} + +#endif /* NSPEAKER > 0 */ +/* spkr.c ends here */ diff --git a/sys/i386/Makefile b/sys/i386/Makefile new file mode 100644 index 000000000000..0662e28ce8ac --- /dev/null +++ b/sys/i386/Makefile @@ -0,0 +1,24 @@ +# @(#)Makefile 7.3 (Berkeley) 6/9/91 + +# Makefile for i386 tags file + +all: + @echo "make tags or links only" + +TI386= ../i386/tags +SI386= ../i386/i386/*.[ch] ../i386/include/*.h ../i386/isa/*.[ch] +AI386= ../i386/i386/*.s + +# Directories in which to place i386 tags links +DI386= eisa isa mca include + +tags: + -ctags -dtf ${TI386} ${COMM} ${SI386} + egrep "^ENTRY(.*)|^ALTENTRY(.*)" ${AI386} | \ + sed "s;\([^:]*\):\([^(]*\)(\([^, )]*\)\(.*\);\3 \1 /^\2(\3\4$$/;" \ + >> ${TI386} + sort -o ${TI386} ${TI386} + +links: + -for i in ${DI386}; do \ + cd $$i && rm -f tags; ln -s ../tags tags; done diff --git a/sys/i386/boot/Makefile b/sys/i386/boot/Makefile new file mode 100644 index 000000000000..bebd8bcc0341 --- /dev/null +++ b/sys/i386/boot/Makefile @@ -0,0 +1,131 @@ +# +# Ported to boot 386BSD by Julian Elischer (julian@tfs.com) +# September 1992 +# +# 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. +# +# +# HISTORY +# $Log: Makefile,v $ +# Revision 2.2 92/04/04 11:33:46 rpd +# Fabricated for MACH 3.0 +# [92/03/30 mg32] +# +# Thu Sep 10 22:40:23 PDT 1992 +# Ported to 386BSD by Julian Elischer +# julian@tfs.com +# + +CFLAGS = -O -DDO_BAD144 +LIBS= -lc +INC= -I../.. + +# start.o should be first, table.o should be second +OBJS = start.o table.o boot2.o boot.o asm.o bios.o io.o disk.o sys.o + +.SUFFIXES: .s .c .o + +# These are wierd because we don't want separate code and data segments.. ok? +.c.o: + @echo $(CC) -c $(CFLAGS) $(INC) $*.c + -@trap "/bin/rm -f $*.i $*.s; exit 0" 0 1 2 3 10 15; \ + $(CC) $(CFLAGS) $(INC) -S $<; \ + if [ $$? != 0 ]; then :; else \ + sed -f boot.sed $*.s > $*.i; \ + $(AS) $*.i -o $@; \ + fi + +.s.o: + @echo $(AS) -o $*.o $< + -@trap "/bin/rm -f $*.i X$*.c; exit 0" 0 1 2 3 10 15; \ + /bin/rm -f X$*.c; \ + ln $*.s X$*.c; \ + $(CC) -E $(CFLAGS) X$*.c > $*.i; \ + if [ $$? != 0 ]; then :; \ + else \ + $(AS) $*.i -o $@; \ + fi + + +boot: boot.sed $(OBJS) + $(LD) -N -T 0 -o boot $(OBJS) $(LIBS) + cp boot boot.sym + @strip boot + @./rmaouthdr boot boot.tmp + @mv -f boot.tmp boot + @ls -l boot + +biosboot: boot + dd if=boot of=biosboot count=1 + +bootbios: boot + dd if=boot of=bootbios skip=1 + +/usr/mdec/bootsd: bootbios + cp bootbios /usr/mdec/bootsd + +/usr/mdec/sdboot: biosboot + cp biosboot /usr/mdec/sdboot + +/usr/mdec/bootwd: /usr/mdec/bootsd + rm -f /usr/mdec/bootwd + ln /usr/mdec/bootsd /usr/mdec/bootwd + +/usr/mdec/wdboot: /usr/mdec/sdboot + rm -f /usr/mdec/wdboot + ln /usr/mdec/sdboot /usr/mdec/wdboot + +/usr/mdec/bootfd: /usr/mdec/bootsd + rm -f /usr/mdec/bootfd + ln /usr/mdec/bootsd /usr/mdec/bootfd + +/usr/mdec/fdboot: /usr/mdec/sdboot + rm -f /usr/mdec/fdboot + ln /usr/mdec/sdboot /usr/mdec/fdboot + +sd: /usr/mdec/bootsd /usr/mdec/sdboot +wd: /usr/mdec/bootwd /usr/mdec/wdboot +fd: /usr/mdec/bootfd /usr/mdec/fdboot + +#wd0: /usr/mdec/bootwd /usr/mdec/wdboot +# disklabel -r -w wd0 julian julian5 /usr/mdec/wdboot /usr/mdec/bootwd +# + +sd0: /usr/mdec/bootsd /usr/mdec/sdboot + disklabel -r -w sd0 XT-8760 scsitest /usr/mdec/sdboot /usr/mdec/bootsd + + +#fd0: /usr/mdec/bootfd /usr/mdec/fdboot +# disklabel -r -w fd0 floppy5 bootflpy /usr/mdec/fdboot /usr/mdec/bootfd +# + +install: wd sd +# you should use the old floppy booter, it's MUCH faster +# This one works but it's too slow. +# besides how many kernels can you fit on a floppy? +# only use this one if you want to boot a kernel +# from a hard disk 2 when you've trashed hard disk 1 +#install: wd sd fd + +clean: + /bin/rm -f *.o *.d boot bootbios biosboot boot.sym + + diff --git a/sys/i386/boot/README.386BSD b/sys/i386/boot/README.386BSD new file mode 100644 index 000000000000..ae61346800cb --- /dev/null +++ b/sys/i386/boot/README.386BSD @@ -0,0 +1,149 @@ +This Boot code is different from the original boot code that came with +386BSD in that it uses the BIOS to load the kernel and to provide all i/o +services. The advantage ofthis is that the same boot code exactly, can run +on any device that is supported by the BIOS. (That's most of them) +This is important for the 'generic scsi' project because it means we can +write drivers for new scsi adapters without having to develop an new +set of boot blocks for each. + +At this point you should read the first part of README.MACH... come back here +when you have done that: + +In normal operation, when co-existing with other operating systems, the +following operations occur: + +1/ the BIOS loads the first block of the disk (called the Master Boot Record +or MBR) and if it has the correct magic numbers, jumps into it: + +2/ The MBR code, looks at the Partition table that is embedded within it, +to detirmine which is the partition to boot from. If you are using the os-bs +bootblocks (highly recommended) then it will give you a menu to choose from. + +3/ The MBR will load the first record of the selected partition and +if it has (the same) magic numbers, jumps into it. In 386bsd this is the +first stage boot, (or boot1) it is represented in /usr/mdec by +wdboot, asboot and sdboot. If the disk has been set up without DOS partitioning +then this block will be at block zero, and will have been loaded directly by +the BIOS. + +4/ Boot1 will look at block0 (which might be itself if there are no DOS +partitions) and will find the 386bsd partition, and using the information +regarding the start position of that partition, will load the next 13 sectors +or so, to around 90000 (640k - 64k). and will jump into it at the appropriate +entry point. Since boot1 and boot2 were compiled together as one file +and then split later, boot1 knows the exact position within boot2 of the +entry point. + +Boot 1 also contains a compiled in DOS partition table +(in case it is at block 0), which contains a 386bsd partition starting +at 0. This ensures that the same code can work whether or not +boot1 is at block 0. + +5/ Boot2 asks the user for a boot device, partition and filename, and then +loads the MBR of the selected device. This may or may not be the device +which was originally used to boot the first MBR. The partition table +of the new MBR is searched for a 386bsd partition, and if one is found, +that is then in turn searched for the disklabel. This could all be on the +second disk at this point, if the user selected it. + +6/On finding the disklabel, boot2 can find the correct unix partition +within the 386bsd partition, and using cutdown filesystem code, +look for the file to boot (e.g. 386bsd). + +7/ Boot2 loads this file starting at the location specified by the a.out header, +(see later) and leaps into it at the location specified in he header. + +if the file does not exist or cannot be loaded, boot2 goes back to step 5. + +386bsd is now running and will hopefully start vm etc. and get to multi-user +mode. + +########################################################################## +During all these steps, all i/o is performed using the BIOS. This has a number +of side effects: + +1/ Since BIOS disk calls are specified in terms of cylinder,head and sector, +and the BIOS read the disk information from either the CMOS or from some other +location which is un-available to us, we must use the cyl,head,sec information +that is given in the MBR, rather than the start address in the MBR, because +we cannot guarentee that we can corectly calculate C,H,S from the start address. + +Therefore, the C,H,S information in the MBR must be as correct for this boot +to work as it would be for DOS to boot. For example, adaptec BIOS routines +assume a layout of 64 heads and 32 sectors giving 1MB per ficticious cylinder. +You must use these figures to calculate the correct values. Luckily, the DOS +fdisk program will do all this for you if you tell it to give you a DOS +partition, and you can change it to a 386BSD partition later. If you use +no DOS partitioning, then the compiled in table in Boot1 will do just fine. + +If you want to do it by hand remember that BIOS counts sectors starting at 1. +(cylinders and heads start at 0 (??)) + +2/ you cannot overwrite the bottom 4k of ram until you have finished ALL +bios calls, as BIOS uses this area as scratch memory. + +3/ Since BIOS runs in REAL mode, and Boot2 runs in protected mode, +Boot 2 switches back to real mode just before each BIOS call and then +back to protected mode on each return. Touch this at your peril.! + +######################################################################### +In answering the prompt from Boot2: +you can, +1/ leave it alone.. it will boot the indicated file from the first +partition of the first drive seen by the BIOS (C:) + +2/ enter only "-s" to boot the default to single user mode + +3/ enter only a filename (optionally with -s) to boot that kernel, + +4/ enter a whole line of the form shown in the prompt. This allows you to +boot some other partition, possibly on the second drive, as root. + + +########################################################################## +In the case you have two drives the same type (both scsi or bith IDE/ESDI), +wd(0,a)xxx + will boot xxx from drive 0, a partition. +wd(1,a)xxx + will boot xxx from drive 1, a partition. + +similarly for sd. + +if you have one wd drive and one scsi drive, then you MUST +use device 'hd' + +otherwise the following will happen: + +with wd0 and sd0, you specify sd1 or wd1 to indicate the 2nd drive. +it boots the kernel correctly, then tells the kernel to use sd1 as root. +you however may not have an sd1, and problems arise. + +hd is special in that the kernel is always told to use unit 0, +The correct TYPE of device will be specified too, so the kernel +will be told either sd0 or wd0. + +Whether sd or wd is specified to the kernel is read from the disklabel, +so ensure that all SCSI disks have type SCSI in their disklabel or the +boot code will assume they are ESDI or IDE. (Remember, because it is +working through the BIOS it has ho idea what kind of disk it is. + +########################################################################## +Installing: +The makefile supplied has a target install which will create the +files wdboot,bootwd ,sdboot and bootsd in /usr/mdec. +BEWARE these will overwrite the existing wdboot and bootwd. (so back +them up) + +there are also targets wd and sd which wil only do one of them + +The commented out targets wd0 and sd0 are examples of how to +load the new bootblocks, however,make sure you change the +device type and label to suit your drive if you uncomment them. +(see 'man disklabel') + +If you already have made partitions using the old bootblocks +these should install painlessly. + +Before you do this ensure you have a booting floppy with correct +disktab and bootblock files on it so that if it doesn't work, you can +re-disklabel from the floppy. diff --git a/sys/i386/boot/README.MACH b/sys/i386/boot/README.MACH new file mode 100644 index 000000000000..d11f3e420372 --- /dev/null +++ b/sys/i386/boot/README.MACH @@ -0,0 +1,218 @@ +/* + * Ported to boot 386BSD by Julian Elischer, September 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: README,v $ + * Revision 2.2 92/04/04 11:33:55 rpd + * From 2.5 + * [92/03/30 mg32] + * + */ + +********NOTE: This is not all relevant to the 386BSD version********** + + AT386 Protected Mode Bootstrap Loader + ===================================== + +1. Overview of Startup + ------------------- + + After the system is rebooted, the BIOS bootstrap routine reads Sector + 1, Track 0 into memory at location 0000:7C00H. If location 0000:7DFEH + (last two bytes of that sector) contains the value AA55H, the BIOS + bootstrap routine will transfer control to 0000:7C00H. Otherwise, the + boot code in that sector is bad and the boot routine stops. + + For DOS compatibility reason, one extra stage of boot is required if + the boot device is a hard disk. The first sector of the hard disk will + contain the MOS-DOS boot code and a boot record partition table. + When this sector is loaded into 0000:7C00H, it will relocate itself + to somewhere else and then load the first sector of the active + partition into 0000:7C00H. Both UNIX and DOS use the command "fdisk" +[ 386bsd does not have an 'fdisk' (yet) ] + to install this first sector into the hard disk and to manipulate + the hard disk partitions. + + + +2. The First Stage Bootstrap Loader + -------------------------------- + + After startup, the first stage boot is loaded at 0000:7C00H. This + first stage boot will load itself and the second stage boot into + memory at location 0000:1000H. For floppy disks, the first cylinder + is reserved as the boot cylinder, and the boot code (first and second) + will be loaded from there. Currently, only double sided, high density + (15 sectors per track) floppies are supported. For hard disks, the + first 29 sectors of the active partition is reserved for boot code + which will be loaded by the first stage boot. All the disk types + recognized by BIOS are supported by this bootstrap loader. +[for 386bsd we load the second stage booter to 9000:0] + + + +3. The Second Stage Bootstrap Loader + -------------------------------- + + After the boot code is loaded, the control is passed to the second + stage bootstrap loader "boot2()". In order to be able to load the + big kernel image (bigger than 512K or 640K, depends on the memory + configuration), the second stage boot loader will run on the protected + mode. This bootstarp loader does not have any stand alone device + drivers, all the I/O's are through the BIOS calls. Since the first + stage boot code will no longer be used at this moment, the memory + location of the first stage boot code (0000:1000H to 0000:1200H) will + be used as an internal buffer for BIOS calls. Immediately after this + internal buffer is the GDT table for the second stage boot loader. + Since this boot loader needs to switch back and forth between protected + and real mode in order to use BIOS calls, the limit of the boot code + and boot data segments must not be greater than 64K. + + The boot loader loads the kernel image at memory location above 1 MB + to skip the memory hole between 521K/640K and 1MB. After the kernel + is loaded, the boot loader stores the information in the stack and + then passes control to kernel. Currently, the three information passed + fromm the boot loader to the kernel are type of the boot device, size + of the base memory and size of the extended memory. + +[ 386bsd receives: howto, bootdev] + +[ 386bsd is loaded where-ever the "MByte" bits of the load address specify, +so if you link it for FE100000 it will load to 1MB, but if you link +it for FE000000 it will load ad 0MB] + +[for machines with only 512KB normal ram the kernel will need to be linked +for 1MB and the bootblocks modified to run below 512KB. (8000:0)] + + +4. The UNIX Startup + ---------------- + + Since the boot loader loads the kernel image at memory location above + 1MB, the kernel has to start as protected mode. In addition, the + link editor description file (vuifile) has to indicate that + the text and data segments start above 1MB. Also, the boot loader + passes the infomation to the kernel through the stack. + +[MOST of what is mentionned below is NOT relevant to 386bsd] + +5. Disk Layout and Bad Block Handling + --------------------------------- + + The System V/386 Release 3.2 (AT) disk layout will be used as the disk + layout for the MACH System on the AT platform. + + This disk layout is as follows: + + * Reserve the first sector of cylinder 0 for the DOS boot record which + contains the master boot code (446 bytes) and the partition table. + (Refer to DOS Technical Reference Manual page 9-6 to 9-10). + + * Reserve the first 29 sectors of the UNIX partition for the first + and the second stage bootstrap. + + * Reserve the 30th sector of the UNIX partition for the pdinfo and + the vtoc tables. + + * Reserve the 31st to the 34th sectors of the UNIX partition for the + bad track and the bad block mapping tables. + + * Reserve up to 253 consecutive tracks when required, beginning with + the 35th sector of the UNIX partition, for alternate tracks. + + * Reserve up to 253 consecutive blocks, beginning with the first + sector after the alternate tracks area, for alternate blocks. + + SEC + 1 + ---------------------------------------------------- + | X | | CYL 0, TRK 0 + ---------------- .......... -------------------- + | .......... | + ---------------- .......... -------------------- + | .......... | + =============================================================== + ^ | BOOTSTRAP | CYL N, TRK M + | ---------------------------------------------------- + | | |30 |31 |32 |33 |34 | + ---------------------------------------------------- --- + U | .......... | ^ + N ---------------- .......... --------------------- | + I | .......... | Alternate Tracks + X ---------------- .......... --------------------- | + | .......... | V + P ---------------------------------------------------- --- + A | .......... | ^ + R ---------------- .......... --------------------- | + T | .......... | Alternate Blocks + I ---------------- .......... -------------------- | + T | .......... | V + I ---------------------------------------------------- --- + O | Unix root partition starts from here | + N ---------------- ----------------- + | | + ---------------------------------------------------- + | | + ---------------------------------------------------- + | | + | --------------------------------------------------- + | | | + | ---------------------------------------------------- + V | | + =============================================================== + | ........ | + --------------- ........ -------------- + | ........ | + ---------------------------------------------------- + + + The bad block handling mechanism is as follows: + + * Use the alternate track in the alternate tracks area if the + track containing the target sector is bad. + + * Use the alternate block in the alternate blocks area if the + target sector is bad. + + + + +6. How to make: + ----------- + + Since the kernel image is loaded above 1 MB, the kernel must start + as protected mode. This means that this bootstrap loader will work + only when the corresponding changes on the kernel startup code are done. + + The make command to generate this bootstrap loader is: + + make -f boot.mk fdboot (floppy boot loader) + make -f boot.mk hdboot (wini boot loader) +[to make 386bsd bootblocks "make sd wd" (warning: they will be installed +in /dev/mdec.. take backups)] diff --git a/sys/i386/boot/asm.h b/sys/i386/boot/asm.h new file mode 100644 index 000000000000..9b86637f4ace --- /dev/null +++ b/sys/i386/boot/asm.h @@ -0,0 +1,192 @@ +/* + * Ported to Boot 386BSD by Julian Elsicher (julian@tfs.com) Sept. 1992 + * + * 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. + */ +/* + * HISTORY + * $Log: asm.h,v $ + * Revision 2.7 92/02/29 15:33:41 rpd + * Added ENTRY2. + * [92/02/28 rpd] + * + * Revision 2.6 92/02/19 15:07:52 elf + * Changed #if __STDC__ to #ifdef __STDC__ + * [92/01/16 jvh] + * + * Revision 2.5 91/05/14 16:02:45 mrt + * Correcting copyright + * + * Revision 2.4 91/02/05 17:10:42 mrt + * Changed to new Mach copyright + * [91/02/01 17:30:29 mrt] + * + * Revision 2.3 90/12/20 16:35:27 jeffreyh + * changes for __STDC__ + * [90/12/06 jeffreyh] + * + * Revision 2.2 90/05/03 15:24:12 dbg + * First checkin. + * + * + * Typo on ENTRY if gprof + * [90/03/29 rvb] + * + * fix SVC for "ifdef wheeze" [kupfer] + * Fix the GPROF definitions. + * ENTRY(x) gets profiled iffdef GPROF. + * Entry(x) (and DATA(x)) is NEVER profiled. + * MCOUNT can be used by asm that intends to build a frame, + * after the frame is built. + * [90/02/26 rvb] + * + * Add #define addr16 .byte 0x67 + * [90/02/09 rvb] + * Added LBi, SVC and ENTRY + * [89/11/10 09:51:33 rvb] + * + * New a.out and coff compatible .s files. + * [89/10/16 rvb] + */ + + +#define S_ARG0 4(%esp) +#define S_ARG1 8(%esp) +#define S_ARG2 12(%esp) +#define S_ARG3 16(%esp) + +#define FRAME pushl %ebp; movl %esp, %ebp +#define EMARF leave + +#define B_ARG0 8(%ebp) +#define B_ARG1 12(%ebp) +#define B_ARG2 16(%ebp) +#define B_ARG3 20(%ebp) + +#ifdef wheeze + +#define ALIGN 4 +#define EXT(x) x +#define LEXT(x) x: +#define LCL(x) ./**/x + +#define LB(x,n) ./**/x +#define LBb(x,n) ./**/x +#define LBf(x,n) ./**/x + +#define SVC lcall $7,$0 + +#define String .string +#define Value .value +#define Times(a,b) [a\*b] +#define Divide(a,b) [a\\b] + +#define INB inb (%dx) +#define OUTB outb (%dx) +#define INL inl (%dx) +#define OUTL outl (%dx) + +#else wheeze +#define ALIGN +#define LCL(x) x + +#define LB(x,n) n +#ifdef __STDC__ +#define EXT(x) _ ## x +#define LEXT(x) _ ## x ## : + +#define LBb(x,n) n ## b +#define LBf(x,n) n ## f +#else __STDC__ +#define EXT(x) _/**/x +#define LEXT(x) _/**/x/**/: +#define LBb(x,n) n/**/b +#define LBf(x,n) n/**/f +#endif __STDC__ +#define SVC .byte 0x9a; .long 0; .word 0x7 + +#define String .ascii +#define Value .word +#define Times(a,b) (a*b) +#define Divide(a,b) (a/b) + +#define INB inb %dx, %al +#define OUTB outb %al, %dx +#define INL inl %dx, %eax +#define OUTL outl %eax, %dx + +#endif wheeze + +#define data32 .byte 0x66 +#define data16 .byte 0x66 +#define addr16 .byte 0x67 + + + +#ifdef GPROF +#ifdef __STDC__ + +#define MCOUNT .data; LB(x, 9); .long 0; .text; lea LBb(x, 9),%edx; call mcount +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + .align ALIGN; LEXT(x) LEXT(y) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; +#define ASENTRY(x) .globl x; .align ALIGN; x ## : ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; + +#else __STDC__ + +#define MCOUNT .data; LB(x, 9): .long 0; .text; lea LBb(x, 9),%edx; call mcount +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + .align ALIGN; LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; .align ALIGN; x: ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; + +#endif __STDC__ +#else GPROF +#ifdef __STDC__ + +#define MCOUNT +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + .align ALIGN; LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; .align ALIGN; x ## : + +#else __STDC__ + +#define MCOUNT +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + .align ALIGN; LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; .align ALIGN; x: + +#endif __STDC__ +#endif GPROF + +#define Entry(x) .globl EXT(x); .align ALIGN; LEXT(x) +#define DATA(x) .globl EXT(x); .align ALIGN; LEXT(x) diff --git a/sys/i386/boot/asm.s b/sys/i386/boot/asm.s new file mode 100644 index 000000000000..8802b13f6d32 --- /dev/null +++ b/sys/i386/boot/asm.s @@ -0,0 +1,270 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: asm.s,v $ + * Revision 2.2 92/04/04 11:34:13 rpd + * Fix Intel Copyright as per B. Davies authorization. + * [92/04/03 rvb] + * From 2.5 boot: pruned inb(), outb(), and pzero(). + * [92/03/30 rvb] + * + * Revision 2.2 91/04/02 14:35:10 mbj + * Added _sp() => where is the stack at. [kupfer] + * Add Intel copyright + * [90/02/09 rvb] + * + */ + +/* + Copyright 1988, 1989, 1990, 1991, 1992 + 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. +*/ + + .file "asm.s" + +#include "asm.h" + + +CR0_PE_ON = 0x1 +CR0_PE_OFF = 0xfffffffe + +.globl _ouraddr + .text + +/* +# +# real_to_prot() +# transfer from real mode to protected mode. +*/ + +ENTRY(real_to_prot) + # guarantee that interrupt is disabled when in prot mode + cli + + # load the gdtr + addr16 + data32 + lgdt EXT(Gdtr) + + # set the PE bit of CR0 + mov %cr0, %eax + + data32 + or $CR0_PE_ON, %eax + mov %eax, %cr0 + + # make intrasegment jump to flush the processor pipeline and + # reload CS register + data32 + ljmp $0x18, $xprot + +xprot: + # we are in USE32 mode now + # set up the protective mode segment registers : DS, SS, ES + mov $0x20, %eax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + ret + +/* +# +# prot_to_real() +# transfer from protected mode to real mode +# +*/ + +ENTRY(prot_to_real) + + # set up a dummy stack frame for the second seg change. + movl _ouraddr, %eax + sarl $4, %eax + pushw %ax + pushw $xreal + + # Change to use16 mode. + ljmp $0x28, $x16 + +x16: + # clear the PE bit of CR0 + mov %cr0, %eax + data32 + and $CR0_PE_OFF, %eax + mov %eax, %cr0 + + + # make intersegment jmp to flush the processor pipeline + # using the fake stack frame set up earlier + # and reload CS register + lret + + +xreal: + # we are in real mode now + # set up the real mode segment registers : DS, SS, ES + movw %cs, %ax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + data32 + ret + +/* +# +# startprog(phyaddr) +# start the program on protected mode where phyaddr is the entry point +# +*/ + +ENTRY(startprog) + push %ebp + mov %esp, %ebp + + + + # get things we need into registers + movl 0x8(%ebp), %ecx # entry offset + movl 0x0c(%ebp), %eax # &argv + + # make a new stack at 0:0xa0000 (big segs) + mov $0x10, %ebx + movw %bx, %ss + movl $0xa0000,%ebx + movl %ebx,%esp + + + # push some number of args onto the stack + pushl $0 # nominally a cyl offset in the boot. + pushl 0x8(%eax) # argv[2] = bootdev + pushl 0x4(%eax) # argv[1] = howto + pushl $0 # dummy 'return' address + + # push on our entry address + mov $0x08, %ebx # segment + pushl %ebx + pushl %ecx + + # convert over the other data segs + mov $0x10, %ebx + movw %bx, %ds + movw %bx, %es + + # convert the PC (and code seg) + lret +/* +# +# pbzero( dst, cnt) +# where src is a virtual address and dst is a physical address +*/ + +ENTRY(pbzero) + push %ebp + mov %esp, %ebp + push %es + push %esi + push %edi + push %ecx + + cld + + # set %es to point at the flat segment + mov $0x10, %eax + movw %ax, %es + + mov 0x8(%ebp), %edi # destination + mov 0xc(%ebp), %ecx # count + mov $0x0,%eax # value + + rep + stosb + + pop %ecx + pop %edi + pop %esi + pop %es + pop %ebp + + ret +/* +# +# pcpy(src, dst, cnt) +# where src is a virtual address and dst is a physical address +# +*/ + +ENTRY(pcpy) + push %ebp + mov %esp, %ebp + push %es + push %esi + push %edi + push %ecx + + cld + + # set %es to point at the flat segment + mov $0x10, %eax + movw %ax, %es + + mov 0x8(%ebp), %esi # source + mov 0xc(%ebp), %edi # destination + mov 0x10(%ebp), %ecx # count + + rep + movsb + + pop %ecx + pop %edi + pop %esi + pop %es + pop %ebp + + ret + diff --git a/sys/i386/boot/bios.s b/sys/i386/boot/bios.s new file mode 100644 index 000000000000..d1673a560042 --- /dev/null +++ b/sys/i386/boot/bios.s @@ -0,0 +1,326 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: bios.s,v $ + * Revision 2.2 92/04/04 11:34:26 rpd + * Fix Intel Copyright as per B. Davies authorization. + * [92/04/03 rvb] + * From 2.5 version + * [92/03/30 mg32] + * + * Revision 2.2 91/04/02 14:35:21 mbj + * Add Intel copyright + * [90/02/09 rvb] + * + */ + + +/* + Copyright 1988, 1989, 1990, 1991, 1992 + 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. +*/ + + .file "bios.s" + +#include "asm.h" + .text + +/* +# biosread(dev, cyl, head, sec) +# Read one sector from disk into the internal buffer "intbuf" which +# is the first 512 bytes of the boot loader. +# BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory +# Call with %ah = 0x2 +# %al = number of sectors +# %ch = cylinder +# %cl = sector +# %dh = head +# %dl = drive (0x80 for hard disk, 0x0 for floppy disk) +# %es:%bx = segment:offset of buffer +# Return: +# %al = 0x0 on success; err code on failure +*/ + +ENTRY(biosread) + push %ebp + mov %esp, %ebp + + push %ebx + push %ecx + push %edx + push %es + + movb 0x10(%ebp), %dh + movw 0x0c(%ebp), %cx + xchgb %ch, %cl # cylinder; the highest 2 bits of cyl is in %cl + rorb $2, %cl + movb 0x14(%ebp), %al + orb %al, %cl + incb %cl # sector; sec starts from 1, not 0 + movb 0x8(%ebp), %dl # device + xor %ebx, %ebx # offset -- 0 + # prot_to_real will set %es to BOOTSEG + + call EXT(prot_to_real) # enter real mode + movb $0x2, %ah # subfunction + movb $0x1, %al # number of sectors -- one + + sti + int $0x13 + cli + + mov %eax, %ebx # save return value + + data16 + call EXT(real_to_prot) # back to protected mode + + xor %eax, %eax + movb %bh, %al # return value in %ax + + pop %es + pop %edx + pop %ecx + pop %ebx + pop %ebp + + ret + + +/* +# putc(ch) +# BIOS call "INT 10H Function 0Eh" to write character to console +# Call with %ah = 0x0e +# %al = character +# %bh = page +# %bl = foreground color ( graphics modes) +*/ + + +ENTRY(putc) + push %ebp + mov %esp, %ebp + push %ebx + push %ecx + + movb 0x8(%ebp), %cl + + call EXT(prot_to_real) + + data16 + mov $0x1, %ebx # %bh=0, %bl=1 (blue) + movb $0xe, %ah + movb %cl, %al + sti + int $0x10 # display a byte + cli + + data16 + call EXT(real_to_prot) + + pop %ecx + pop %ebx + pop %ebp + ret + + +/* +# getc() +# BIOS call "INT 16H Function 00H" to read character from keyboard +# Call with %ah = 0x0 +# Return: %ah = keyboard scan code +# %al = ASCII character +*/ + +ENTRY(getc) + push %ebp + mov %esp, %ebp + push %ebx # save %ebx + + call EXT(prot_to_real) + + movb $0x0, %ah + sti + int $0x16 + cli + + movb %al, %bl # real_to_prot uses %eax + + data16 + call EXT(real_to_prot) + + xor %eax, %eax + movb %bl, %al + + pop %ebx + pop %ebp + ret +/* +# ischar() +# if there is a character pending, return it; otherwise return 0 +# BIOS call "INT 16H Function 01H" to check whether a character is pending +# Call with %ah = 0x1 +# Return: +# If key waiting to be input: +# %ah = keyboard scan code +# %al = ASCII character +# Zero flag = clear +# else +# Zero flag = set +*/ +ENTRY(ischar) + push %ebp + mov %esp, %ebp + push %ebx + + call EXT(prot_to_real) # enter real mode + + xor %ebx, %ebx + movb $0x1, %ah + sti + int $0x16 + cli + data16 + jz nochar + movb %al, %bl + +nochar: + data16 + call EXT(real_to_prot) + + xor %eax, %eax + movb %bl, %al + + pop %ebx + pop %ebp + ret + +/* +# +# get_diskinfo(): return a word that represents the +# max number of sectors and heads and drives for this device +# +*/ + +ENTRY(get_diskinfo) + push %ebp + mov %esp, %ebp + push %es + push %ebx + push %ecx + push %edx + + movb 0x8(%ebp), %dl # diskinfo(drive #) + call EXT(prot_to_real) # enter real mode + + movb $0x8, %ah # ask for disk info + + sti + int $0x13 + cli + + data16 + call EXT(real_to_prot) # back to protected mode + + xor %eax, %eax + + /*form a longword representing all this gunk*/ + movb %dh, %ah # # heads + andb $0x3f, %cl # mask of cylinder gunk + movb %cl, %al # # sectors + + pop %edx + pop %ecx + pop %ebx + pop %es + pop %ebp + ret + +/* +# +# memsize(i) : return the memory size in KB. i == 0 for conventional memory, +# i == 1 for extended memory +# BIOS call "INT 12H" to get conventional memory size +# BIOS call "INT 15H, AH=88H" to get extended memory size +# Both have the return value in AX. +# +*/ + +ENTRY(memsize) + push %ebp + mov %esp, %ebp + push %ebx + + mov 8(%ebp), %ebx + + call EXT(prot_to_real) # enter real mode + + cmpb $0x1, %bl + data16 + je xext + + sti + int $0x12 + cli + data16 + jmp xdone + +xext: movb $0x88, %ah + sti + int $0x15 + cli + +xdone: + mov %eax, %ebx + + data16 + call EXT(real_to_prot) + + mov %ebx, %eax + pop %ebx + pop %ebp + ret diff --git a/sys/i386/boot/biosboot/Makefile b/sys/i386/boot/biosboot/Makefile new file mode 100644 index 000000000000..bebd8bcc0341 --- /dev/null +++ b/sys/i386/boot/biosboot/Makefile @@ -0,0 +1,131 @@ +# +# Ported to boot 386BSD by Julian Elischer (julian@tfs.com) +# September 1992 +# +# 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. +# +# +# HISTORY +# $Log: Makefile,v $ +# Revision 2.2 92/04/04 11:33:46 rpd +# Fabricated for MACH 3.0 +# [92/03/30 mg32] +# +# Thu Sep 10 22:40:23 PDT 1992 +# Ported to 386BSD by Julian Elischer +# julian@tfs.com +# + +CFLAGS = -O -DDO_BAD144 +LIBS= -lc +INC= -I../.. + +# start.o should be first, table.o should be second +OBJS = start.o table.o boot2.o boot.o asm.o bios.o io.o disk.o sys.o + +.SUFFIXES: .s .c .o + +# These are wierd because we don't want separate code and data segments.. ok? +.c.o: + @echo $(CC) -c $(CFLAGS) $(INC) $*.c + -@trap "/bin/rm -f $*.i $*.s; exit 0" 0 1 2 3 10 15; \ + $(CC) $(CFLAGS) $(INC) -S $<; \ + if [ $$? != 0 ]; then :; else \ + sed -f boot.sed $*.s > $*.i; \ + $(AS) $*.i -o $@; \ + fi + +.s.o: + @echo $(AS) -o $*.o $< + -@trap "/bin/rm -f $*.i X$*.c; exit 0" 0 1 2 3 10 15; \ + /bin/rm -f X$*.c; \ + ln $*.s X$*.c; \ + $(CC) -E $(CFLAGS) X$*.c > $*.i; \ + if [ $$? != 0 ]; then :; \ + else \ + $(AS) $*.i -o $@; \ + fi + + +boot: boot.sed $(OBJS) + $(LD) -N -T 0 -o boot $(OBJS) $(LIBS) + cp boot boot.sym + @strip boot + @./rmaouthdr boot boot.tmp + @mv -f boot.tmp boot + @ls -l boot + +biosboot: boot + dd if=boot of=biosboot count=1 + +bootbios: boot + dd if=boot of=bootbios skip=1 + +/usr/mdec/bootsd: bootbios + cp bootbios /usr/mdec/bootsd + +/usr/mdec/sdboot: biosboot + cp biosboot /usr/mdec/sdboot + +/usr/mdec/bootwd: /usr/mdec/bootsd + rm -f /usr/mdec/bootwd + ln /usr/mdec/bootsd /usr/mdec/bootwd + +/usr/mdec/wdboot: /usr/mdec/sdboot + rm -f /usr/mdec/wdboot + ln /usr/mdec/sdboot /usr/mdec/wdboot + +/usr/mdec/bootfd: /usr/mdec/bootsd + rm -f /usr/mdec/bootfd + ln /usr/mdec/bootsd /usr/mdec/bootfd + +/usr/mdec/fdboot: /usr/mdec/sdboot + rm -f /usr/mdec/fdboot + ln /usr/mdec/sdboot /usr/mdec/fdboot + +sd: /usr/mdec/bootsd /usr/mdec/sdboot +wd: /usr/mdec/bootwd /usr/mdec/wdboot +fd: /usr/mdec/bootfd /usr/mdec/fdboot + +#wd0: /usr/mdec/bootwd /usr/mdec/wdboot +# disklabel -r -w wd0 julian julian5 /usr/mdec/wdboot /usr/mdec/bootwd +# + +sd0: /usr/mdec/bootsd /usr/mdec/sdboot + disklabel -r -w sd0 XT-8760 scsitest /usr/mdec/sdboot /usr/mdec/bootsd + + +#fd0: /usr/mdec/bootfd /usr/mdec/fdboot +# disklabel -r -w fd0 floppy5 bootflpy /usr/mdec/fdboot /usr/mdec/bootfd +# + +install: wd sd +# you should use the old floppy booter, it's MUCH faster +# This one works but it's too slow. +# besides how many kernels can you fit on a floppy? +# only use this one if you want to boot a kernel +# from a hard disk 2 when you've trashed hard disk 1 +#install: wd sd fd + +clean: + /bin/rm -f *.o *.d boot bootbios biosboot boot.sym + + diff --git a/sys/i386/boot/biosboot/README.386BSD b/sys/i386/boot/biosboot/README.386BSD new file mode 100644 index 000000000000..ae61346800cb --- /dev/null +++ b/sys/i386/boot/biosboot/README.386BSD @@ -0,0 +1,149 @@ +This Boot code is different from the original boot code that came with +386BSD in that it uses the BIOS to load the kernel and to provide all i/o +services. The advantage ofthis is that the same boot code exactly, can run +on any device that is supported by the BIOS. (That's most of them) +This is important for the 'generic scsi' project because it means we can +write drivers for new scsi adapters without having to develop an new +set of boot blocks for each. + +At this point you should read the first part of README.MACH... come back here +when you have done that: + +In normal operation, when co-existing with other operating systems, the +following operations occur: + +1/ the BIOS loads the first block of the disk (called the Master Boot Record +or MBR) and if it has the correct magic numbers, jumps into it: + +2/ The MBR code, looks at the Partition table that is embedded within it, +to detirmine which is the partition to boot from. If you are using the os-bs +bootblocks (highly recommended) then it will give you a menu to choose from. + +3/ The MBR will load the first record of the selected partition and +if it has (the same) magic numbers, jumps into it. In 386bsd this is the +first stage boot, (or boot1) it is represented in /usr/mdec by +wdboot, asboot and sdboot. If the disk has been set up without DOS partitioning +then this block will be at block zero, and will have been loaded directly by +the BIOS. + +4/ Boot1 will look at block0 (which might be itself if there are no DOS +partitions) and will find the 386bsd partition, and using the information +regarding the start position of that partition, will load the next 13 sectors +or so, to around 90000 (640k - 64k). and will jump into it at the appropriate +entry point. Since boot1 and boot2 were compiled together as one file +and then split later, boot1 knows the exact position within boot2 of the +entry point. + +Boot 1 also contains a compiled in DOS partition table +(in case it is at block 0), which contains a 386bsd partition starting +at 0. This ensures that the same code can work whether or not +boot1 is at block 0. + +5/ Boot2 asks the user for a boot device, partition and filename, and then +loads the MBR of the selected device. This may or may not be the device +which was originally used to boot the first MBR. The partition table +of the new MBR is searched for a 386bsd partition, and if one is found, +that is then in turn searched for the disklabel. This could all be on the +second disk at this point, if the user selected it. + +6/On finding the disklabel, boot2 can find the correct unix partition +within the 386bsd partition, and using cutdown filesystem code, +look for the file to boot (e.g. 386bsd). + +7/ Boot2 loads this file starting at the location specified by the a.out header, +(see later) and leaps into it at the location specified in he header. + +if the file does not exist or cannot be loaded, boot2 goes back to step 5. + +386bsd is now running and will hopefully start vm etc. and get to multi-user +mode. + +########################################################################## +During all these steps, all i/o is performed using the BIOS. This has a number +of side effects: + +1/ Since BIOS disk calls are specified in terms of cylinder,head and sector, +and the BIOS read the disk information from either the CMOS or from some other +location which is un-available to us, we must use the cyl,head,sec information +that is given in the MBR, rather than the start address in the MBR, because +we cannot guarentee that we can corectly calculate C,H,S from the start address. + +Therefore, the C,H,S information in the MBR must be as correct for this boot +to work as it would be for DOS to boot. For example, adaptec BIOS routines +assume a layout of 64 heads and 32 sectors giving 1MB per ficticious cylinder. +You must use these figures to calculate the correct values. Luckily, the DOS +fdisk program will do all this for you if you tell it to give you a DOS +partition, and you can change it to a 386BSD partition later. If you use +no DOS partitioning, then the compiled in table in Boot1 will do just fine. + +If you want to do it by hand remember that BIOS counts sectors starting at 1. +(cylinders and heads start at 0 (??)) + +2/ you cannot overwrite the bottom 4k of ram until you have finished ALL +bios calls, as BIOS uses this area as scratch memory. + +3/ Since BIOS runs in REAL mode, and Boot2 runs in protected mode, +Boot 2 switches back to real mode just before each BIOS call and then +back to protected mode on each return. Touch this at your peril.! + +######################################################################### +In answering the prompt from Boot2: +you can, +1/ leave it alone.. it will boot the indicated file from the first +partition of the first drive seen by the BIOS (C:) + +2/ enter only "-s" to boot the default to single user mode + +3/ enter only a filename (optionally with -s) to boot that kernel, + +4/ enter a whole line of the form shown in the prompt. This allows you to +boot some other partition, possibly on the second drive, as root. + + +########################################################################## +In the case you have two drives the same type (both scsi or bith IDE/ESDI), +wd(0,a)xxx + will boot xxx from drive 0, a partition. +wd(1,a)xxx + will boot xxx from drive 1, a partition. + +similarly for sd. + +if you have one wd drive and one scsi drive, then you MUST +use device 'hd' + +otherwise the following will happen: + +with wd0 and sd0, you specify sd1 or wd1 to indicate the 2nd drive. +it boots the kernel correctly, then tells the kernel to use sd1 as root. +you however may not have an sd1, and problems arise. + +hd is special in that the kernel is always told to use unit 0, +The correct TYPE of device will be specified too, so the kernel +will be told either sd0 or wd0. + +Whether sd or wd is specified to the kernel is read from the disklabel, +so ensure that all SCSI disks have type SCSI in their disklabel or the +boot code will assume they are ESDI or IDE. (Remember, because it is +working through the BIOS it has ho idea what kind of disk it is. + +########################################################################## +Installing: +The makefile supplied has a target install which will create the +files wdboot,bootwd ,sdboot and bootsd in /usr/mdec. +BEWARE these will overwrite the existing wdboot and bootwd. (so back +them up) + +there are also targets wd and sd which wil only do one of them + +The commented out targets wd0 and sd0 are examples of how to +load the new bootblocks, however,make sure you change the +device type and label to suit your drive if you uncomment them. +(see 'man disklabel') + +If you already have made partitions using the old bootblocks +these should install painlessly. + +Before you do this ensure you have a booting floppy with correct +disktab and bootblock files on it so that if it doesn't work, you can +re-disklabel from the floppy. diff --git a/sys/i386/boot/biosboot/README.MACH b/sys/i386/boot/biosboot/README.MACH new file mode 100644 index 000000000000..d11f3e420372 --- /dev/null +++ b/sys/i386/boot/biosboot/README.MACH @@ -0,0 +1,218 @@ +/* + * Ported to boot 386BSD by Julian Elischer, September 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: README,v $ + * Revision 2.2 92/04/04 11:33:55 rpd + * From 2.5 + * [92/03/30 mg32] + * + */ + +********NOTE: This is not all relevant to the 386BSD version********** + + AT386 Protected Mode Bootstrap Loader + ===================================== + +1. Overview of Startup + ------------------- + + After the system is rebooted, the BIOS bootstrap routine reads Sector + 1, Track 0 into memory at location 0000:7C00H. If location 0000:7DFEH + (last two bytes of that sector) contains the value AA55H, the BIOS + bootstrap routine will transfer control to 0000:7C00H. Otherwise, the + boot code in that sector is bad and the boot routine stops. + + For DOS compatibility reason, one extra stage of boot is required if + the boot device is a hard disk. The first sector of the hard disk will + contain the MOS-DOS boot code and a boot record partition table. + When this sector is loaded into 0000:7C00H, it will relocate itself + to somewhere else and then load the first sector of the active + partition into 0000:7C00H. Both UNIX and DOS use the command "fdisk" +[ 386bsd does not have an 'fdisk' (yet) ] + to install this first sector into the hard disk and to manipulate + the hard disk partitions. + + + +2. The First Stage Bootstrap Loader + -------------------------------- + + After startup, the first stage boot is loaded at 0000:7C00H. This + first stage boot will load itself and the second stage boot into + memory at location 0000:1000H. For floppy disks, the first cylinder + is reserved as the boot cylinder, and the boot code (first and second) + will be loaded from there. Currently, only double sided, high density + (15 sectors per track) floppies are supported. For hard disks, the + first 29 sectors of the active partition is reserved for boot code + which will be loaded by the first stage boot. All the disk types + recognized by BIOS are supported by this bootstrap loader. +[for 386bsd we load the second stage booter to 9000:0] + + + +3. The Second Stage Bootstrap Loader + -------------------------------- + + After the boot code is loaded, the control is passed to the second + stage bootstrap loader "boot2()". In order to be able to load the + big kernel image (bigger than 512K or 640K, depends on the memory + configuration), the second stage boot loader will run on the protected + mode. This bootstarp loader does not have any stand alone device + drivers, all the I/O's are through the BIOS calls. Since the first + stage boot code will no longer be used at this moment, the memory + location of the first stage boot code (0000:1000H to 0000:1200H) will + be used as an internal buffer for BIOS calls. Immediately after this + internal buffer is the GDT table for the second stage boot loader. + Since this boot loader needs to switch back and forth between protected + and real mode in order to use BIOS calls, the limit of the boot code + and boot data segments must not be greater than 64K. + + The boot loader loads the kernel image at memory location above 1 MB + to skip the memory hole between 521K/640K and 1MB. After the kernel + is loaded, the boot loader stores the information in the stack and + then passes control to kernel. Currently, the three information passed + fromm the boot loader to the kernel are type of the boot device, size + of the base memory and size of the extended memory. + +[ 386bsd receives: howto, bootdev] + +[ 386bsd is loaded where-ever the "MByte" bits of the load address specify, +so if you link it for FE100000 it will load to 1MB, but if you link +it for FE000000 it will load ad 0MB] + +[for machines with only 512KB normal ram the kernel will need to be linked +for 1MB and the bootblocks modified to run below 512KB. (8000:0)] + + +4. The UNIX Startup + ---------------- + + Since the boot loader loads the kernel image at memory location above + 1MB, the kernel has to start as protected mode. In addition, the + link editor description file (vuifile) has to indicate that + the text and data segments start above 1MB. Also, the boot loader + passes the infomation to the kernel through the stack. + +[MOST of what is mentionned below is NOT relevant to 386bsd] + +5. Disk Layout and Bad Block Handling + --------------------------------- + + The System V/386 Release 3.2 (AT) disk layout will be used as the disk + layout for the MACH System on the AT platform. + + This disk layout is as follows: + + * Reserve the first sector of cylinder 0 for the DOS boot record which + contains the master boot code (446 bytes) and the partition table. + (Refer to DOS Technical Reference Manual page 9-6 to 9-10). + + * Reserve the first 29 sectors of the UNIX partition for the first + and the second stage bootstrap. + + * Reserve the 30th sector of the UNIX partition for the pdinfo and + the vtoc tables. + + * Reserve the 31st to the 34th sectors of the UNIX partition for the + bad track and the bad block mapping tables. + + * Reserve up to 253 consecutive tracks when required, beginning with + the 35th sector of the UNIX partition, for alternate tracks. + + * Reserve up to 253 consecutive blocks, beginning with the first + sector after the alternate tracks area, for alternate blocks. + + SEC + 1 + ---------------------------------------------------- + | X | | CYL 0, TRK 0 + ---------------- .......... -------------------- + | .......... | + ---------------- .......... -------------------- + | .......... | + =============================================================== + ^ | BOOTSTRAP | CYL N, TRK M + | ---------------------------------------------------- + | | |30 |31 |32 |33 |34 | + ---------------------------------------------------- --- + U | .......... | ^ + N ---------------- .......... --------------------- | + I | .......... | Alternate Tracks + X ---------------- .......... --------------------- | + | .......... | V + P ---------------------------------------------------- --- + A | .......... | ^ + R ---------------- .......... --------------------- | + T | .......... | Alternate Blocks + I ---------------- .......... -------------------- | + T | .......... | V + I ---------------------------------------------------- --- + O | Unix root partition starts from here | + N ---------------- ----------------- + | | + ---------------------------------------------------- + | | + ---------------------------------------------------- + | | + | --------------------------------------------------- + | | | + | ---------------------------------------------------- + V | | + =============================================================== + | ........ | + --------------- ........ -------------- + | ........ | + ---------------------------------------------------- + + + The bad block handling mechanism is as follows: + + * Use the alternate track in the alternate tracks area if the + track containing the target sector is bad. + + * Use the alternate block in the alternate blocks area if the + target sector is bad. + + + + +6. How to make: + ----------- + + Since the kernel image is loaded above 1 MB, the kernel must start + as protected mode. This means that this bootstrap loader will work + only when the corresponding changes on the kernel startup code are done. + + The make command to generate this bootstrap loader is: + + make -f boot.mk fdboot (floppy boot loader) + make -f boot.mk hdboot (wini boot loader) +[to make 386bsd bootblocks "make sd wd" (warning: they will be installed +in /dev/mdec.. take backups)] diff --git a/sys/i386/boot/biosboot/asm.h b/sys/i386/boot/biosboot/asm.h new file mode 100644 index 000000000000..9b86637f4ace --- /dev/null +++ b/sys/i386/boot/biosboot/asm.h @@ -0,0 +1,192 @@ +/* + * Ported to Boot 386BSD by Julian Elsicher (julian@tfs.com) Sept. 1992 + * + * 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. + */ +/* + * HISTORY + * $Log: asm.h,v $ + * Revision 2.7 92/02/29 15:33:41 rpd + * Added ENTRY2. + * [92/02/28 rpd] + * + * Revision 2.6 92/02/19 15:07:52 elf + * Changed #if __STDC__ to #ifdef __STDC__ + * [92/01/16 jvh] + * + * Revision 2.5 91/05/14 16:02:45 mrt + * Correcting copyright + * + * Revision 2.4 91/02/05 17:10:42 mrt + * Changed to new Mach copyright + * [91/02/01 17:30:29 mrt] + * + * Revision 2.3 90/12/20 16:35:27 jeffreyh + * changes for __STDC__ + * [90/12/06 jeffreyh] + * + * Revision 2.2 90/05/03 15:24:12 dbg + * First checkin. + * + * + * Typo on ENTRY if gprof + * [90/03/29 rvb] + * + * fix SVC for "ifdef wheeze" [kupfer] + * Fix the GPROF definitions. + * ENTRY(x) gets profiled iffdef GPROF. + * Entry(x) (and DATA(x)) is NEVER profiled. + * MCOUNT can be used by asm that intends to build a frame, + * after the frame is built. + * [90/02/26 rvb] + * + * Add #define addr16 .byte 0x67 + * [90/02/09 rvb] + * Added LBi, SVC and ENTRY + * [89/11/10 09:51:33 rvb] + * + * New a.out and coff compatible .s files. + * [89/10/16 rvb] + */ + + +#define S_ARG0 4(%esp) +#define S_ARG1 8(%esp) +#define S_ARG2 12(%esp) +#define S_ARG3 16(%esp) + +#define FRAME pushl %ebp; movl %esp, %ebp +#define EMARF leave + +#define B_ARG0 8(%ebp) +#define B_ARG1 12(%ebp) +#define B_ARG2 16(%ebp) +#define B_ARG3 20(%ebp) + +#ifdef wheeze + +#define ALIGN 4 +#define EXT(x) x +#define LEXT(x) x: +#define LCL(x) ./**/x + +#define LB(x,n) ./**/x +#define LBb(x,n) ./**/x +#define LBf(x,n) ./**/x + +#define SVC lcall $7,$0 + +#define String .string +#define Value .value +#define Times(a,b) [a\*b] +#define Divide(a,b) [a\\b] + +#define INB inb (%dx) +#define OUTB outb (%dx) +#define INL inl (%dx) +#define OUTL outl (%dx) + +#else wheeze +#define ALIGN +#define LCL(x) x + +#define LB(x,n) n +#ifdef __STDC__ +#define EXT(x) _ ## x +#define LEXT(x) _ ## x ## : + +#define LBb(x,n) n ## b +#define LBf(x,n) n ## f +#else __STDC__ +#define EXT(x) _/**/x +#define LEXT(x) _/**/x/**/: +#define LBb(x,n) n/**/b +#define LBf(x,n) n/**/f +#endif __STDC__ +#define SVC .byte 0x9a; .long 0; .word 0x7 + +#define String .ascii +#define Value .word +#define Times(a,b) (a*b) +#define Divide(a,b) (a/b) + +#define INB inb %dx, %al +#define OUTB outb %al, %dx +#define INL inl %dx, %eax +#define OUTL outl %eax, %dx + +#endif wheeze + +#define data32 .byte 0x66 +#define data16 .byte 0x66 +#define addr16 .byte 0x67 + + + +#ifdef GPROF +#ifdef __STDC__ + +#define MCOUNT .data; LB(x, 9); .long 0; .text; lea LBb(x, 9),%edx; call mcount +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + .align ALIGN; LEXT(x) LEXT(y) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; +#define ASENTRY(x) .globl x; .align ALIGN; x ## : ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; + +#else __STDC__ + +#define MCOUNT .data; LB(x, 9): .long 0; .text; lea LBb(x, 9),%edx; call mcount +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + .align ALIGN; LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; .align ALIGN; x: ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; + +#endif __STDC__ +#else GPROF +#ifdef __STDC__ + +#define MCOUNT +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + .align ALIGN; LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; .align ALIGN; x ## : + +#else __STDC__ + +#define MCOUNT +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + .align ALIGN; LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; .align ALIGN; x: + +#endif __STDC__ +#endif GPROF + +#define Entry(x) .globl EXT(x); .align ALIGN; LEXT(x) +#define DATA(x) .globl EXT(x); .align ALIGN; LEXT(x) diff --git a/sys/i386/boot/biosboot/boot.c b/sys/i386/boot/biosboot/boot.c new file mode 100644 index 000000000000..805303e6dab2 --- /dev/null +++ b/sys/i386/boot/biosboot/boot.c @@ -0,0 +1,323 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00159 + * -------------------- ----- ---------------------- + * + * 23 May 93 Rodney W. Grimes Added pad to kernel size for structs + * allocated by locore.s + */ + +/* + * HISTORY + * $Log: boot.c,v $ + * Revision 2.2 92/04/04 11:34:37 rpd + * Change date in banner. + * [92/04/03 16:51:14 rvb] + * + * Fix Intel Copyright as per B. Davies authorization. + * [92/04/03 rvb] + * From 2.5 version. + * [92/03/30 mg32] + * + */ + +/* + Copyright 1988, 1989, 1990, 1991, 1992 + 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 "boot.h" +#include <a.out.h> +#include <sys/reboot.h> + + +struct exec head; +int argv[10], esym; +char *name; +char *names[] = { + "/386bsd", "/386bsd.old", + "/vmunix", "/vmunix.old" +}; +#define NUMNAMES (sizeof(names)/sizeof(char *)) + +extern int end; +boot(drive) +int drive; +{ + int loadflags, currname = 0; + printf("\n>> 386bsd BOOT @ 0x%x: %d/%d k of memory [20/9/92]\n", + ouraddr, + argv[7] = memsize(0), + argv[8] = memsize(1)); + printf("use options hd(1,...... to boot sd0 when wd0 is also installed\n"); + gateA20(); +loadstart: + /***************************************************************\ + * As a default set it to the first partition of the first * + * floppy or hard drive * + \***************************************************************/ + part = unit = 0; + maj = (drive&0x80 ? 0 : 2); /* a good first bet */ + name = names[currname++]; + + loadflags = 0; + if (currname == NUMNAMES) + currname = 0; + getbootdev(&loadflags); + if (openrd()) { + printf("Can't find %s\n", name); + goto loadstart; + } +/* if (inode.i_mode&IEXEC) + loadflags |= RB_KDB; +*/ + loadprog(loadflags); + goto loadstart; +} + +loadprog(howto) + int howto; +{ + long int startaddr; + long int addr; /* physical address.. not directly useable */ + int i; + static int (*x_entry)() = 0; + unsigned char tmpbuf[4096]; /* we need to load the first 4k here */ + + argv[3] = 0; + argv[4] = 0; + read(&head, sizeof(head)); + if (head.a_magic == 0413 ) + { + poff = 4096; + } + else + { + printf("Invalid format!\n"); + return; + } + + startaddr = (int)head.a_entry; + addr = (startaddr & 0x00f00000); /* some MEG boundary */ + printf("Booting %s(%d,%c)%s @ 0x%x\n" + , devs[maj] + , unit + , 'a'+part + , name + , addr); + if(addr < ouraddr) + { + if((addr + head.a_text + head.a_data) > ouraddr) + { + printf("kernel will not fit below loader\n"); + return; + } + /* + * The +28672 is for memory allocated by locore.s that must + * fit in the bss! + */ + if((addr + head.a_text + head.a_data + head.a_bss + 28672) > 0xa0000) + { + printf("kernel too big, won't fit in 640K with bss\n"); + printf("Only hope is to link the kernel for > 1MB\n"); + return; + } + if((addr + head.a_text + head.a_data + head.a_bss) > ouraddr) + { + printf("loader overlaps bss, kernel must bzero\n"); + } + } + printf("text=0x%x", head.a_text); + /********************************************************/ + /* LOAD THE TEXT SEGMENT */ + /* don't clobber the first 4k yet (BIOS NEEDS IT) */ + /********************************************************/ + read(tmpbuf,4096); + addr += 4096; + xread(addr, head.a_text - 4096); + addr += head.a_text - 4096; + + /********************************************************/ + /* Load the Initialised data after the text */ + /********************************************************/ + while (addr & CLOFSET) + *(char *)addr++ = 0; + + printf(" data=0x%x", head.a_data); + xread(addr, head.a_data); + addr += head.a_data; + + /********************************************************/ + /* Skip over the uninitialised data */ + /* (but clear it) */ + /********************************************************/ + printf(" bss=0x%x", head.a_bss); + if( (addr < ouraddr) && ((addr + head.a_bss) > ouraddr)) + { + pbzero(addr,ouraddr - (int)addr); + } + else + { + pbzero(addr,head.a_bss); + } + argv[3] = (addr += head.a_bss); + +#ifdef LOADSYMS /* not yet, haven't worked this out yet */ + if (addr > 0x100000) + { + /********************************************************/ + /*copy in the symbol header */ + /********************************************************/ + pcpy(&head.a_syms, addr, sizeof(head.a_syms)); + addr += sizeof(head.a_syms); + + /********************************************************/ + /* READ in the symbol table */ + /********************************************************/ + printf(" symbols=[+0x%x", head.a_syms); + xread(addr, head.a_syms); + addr += head.a_syms; + + /********************************************************/ + /* Followed by the next integer (another header) */ + /* more debug symbols? */ + /********************************************************/ + read(&i, sizeof(int)); + pcpy(&i, addr, sizeof(int)); + i -= sizeof(int); + addr += sizeof(int); + + + /********************************************************/ + /* and that many bytes of (debug symbols?) */ + /********************************************************/ + printf("+0x%x]", i); + xread(addr, i); + addr += i; + } +#endif LOADSYMS + /********************************************************/ + /* and note the end address of all this */ + /********************************************************/ + + argv[4] = ((addr+sizeof(int)-1))&~(sizeof(int)-1); + printf(" total=0x%x",argv[4]); + + + /* + * We now pass the various bootstrap parameters to the loaded + * image via the argument list + * (THIS IS A BIT OF HISTORY FROM MACH.. LEAVE FOR NOW) + * arg1 = boot flags + * arg2 = boot device + * arg3 = start of symbol table (0 if not loaded) + * arg4 = end of symbol table (0 if not loaded) + * arg5 = transfer address from image + * arg6 = transfer address for next image pointer + */ + switch(maj) + { + case 2: + printf("\n\nInsert file system floppy \n"); + getchar(); + break; + case 4: + break; + } + argv[1] = howto; + argv[2] = (MAKEBOOTDEV(maj, 0, 0, unit, part)) ; + argv[5] = (head.a_entry &= 0xfffffff); + argv[6] = (int) &x_entry; + argv[0] = 8; + /****************************************************************/ + /* copy that first page and overwrite any BIOS variables */ + /****************************************************************/ + printf(" entry point=0x%x \n" ,((int)startaddr) & 0xffffff); + pcpy(tmpbuf, 0, 4096); + startprog(((int)startaddr & 0xffffff),argv); +} + +char namebuf[100]; +getbootdev(howto) + int *howto; +{ + char c, *ptr = namebuf; + printf("Boot: [[[%s(%d,%c)]%s][-s][-a][-d]] :- " + , devs[maj] + , unit + , 'a'+part + , name); + if (gets(namebuf)) { + while (c=*ptr) { + while (c==' ') + c = *++ptr; + if (!c) + return; + if (c=='-') + while ((c = *++ptr) && c!=' ') + switch (c) { + case 'a': + *howto |= RB_ASKNAME; continue; + case 's': + *howto |= RB_SINGLE; continue; + case 'd': + *howto |= RB_KDB; continue; + case 'b': + *howto |= RB_HALT; continue; + } + else { + name = ptr; + while ((c = *++ptr) && c!=' '); + if (c) + *ptr++ = 0; + } + } + } +} + diff --git a/sys/i386/boot/biosboot/boot.h b/sys/i386/boot/biosboot/boot.h new file mode 100644 index 000000000000..28a7a220e52c --- /dev/null +++ b/sys/i386/boot/biosboot/boot.h @@ -0,0 +1,48 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: boot.h,v $ + * Revision 2.2 92/04/04 11:35:03 rpd + * Fabricated from 3.0 bootstrap. But too many things are global. + * [92/03/30 mg32] + * + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <ufs/quota.h> +#include <ufs/fs.h> +#include <ufs/inode.h> + +extern char *devs[], *name, *iodest; +extern struct fs *fs; +extern struct inode inode; +extern int dosdev, unit, part, maj, boff, poff, bnum, cnt; +extern long int ouraddr; diff --git a/sys/i386/boot/biosboot/disk.c b/sys/i386/boot/biosboot/disk.c new file mode 100644 index 000000000000..87b30b27fc2c --- /dev/null +++ b/sys/i386/boot/biosboot/disk.c @@ -0,0 +1,238 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: disk.c,v $ + * Revision 2.2 92/04/04 11:35:49 rpd + * Fabricated from 3.0 bootstrap and 2.5 boot disk.c: + * with support for scsi + * [92/03/30 mg32] + * + */ + +/* + * 9/20/92 + * Peng-Toh Sim. sim@cory.berkeley.edu + * Added bad144 support under 386bsd for wd's + * So, bad block remapping is done when loading the kernel. + */ + +#include "boot.h" +#ifdef DO_BAD144 +#include <sys/dkbad.h> +#endif DO_BAD144 +#include <sys/disklabel.h> + +#define BIOS_DEV_FLOPPY 0x0 +#define BIOS_DEV_WIN 0x80 + +#define BPS 512 +#define SPT(di) ((di)&0xff) +#define HEADS(di) ((((di)>>8)&0xff)+1) + +char *devs[] = {"wd", "hd", "fd", "wt", "sd", 0}; + +#ifdef DO_BAD144 +struct dkbad dkb; +int do_bad144; +int bsize; +#endif DO_BAD144 + +int spt, spc; + +char *iodest; +struct fs *fs; +struct inode inode; +int dosdev, unit, part, maj, boff, poff, bnum, cnt; + +/*#define EMBEDDED_DISKLABEL 1*/ +extern struct disklabel disklabel; +/*struct disklabel disklabel;*/ + +devopen() +{ + struct dos_partition *dptr; + struct disklabel *dl; + int dosdev = inode.i_dev; + int i, sector, di; + + di = get_diskinfo(dosdev); + spc = (spt = SPT(di)) * HEADS(di); + if (dosdev == 2) + { + boff = 0; + part = (spt == 15 ? 3 : 1); + } + else + { +#ifdef EMBEDDED_DISKLABEL + dl = &disklabel; +#else EMBEDDED_DISKLABEL + Bread(dosdev, 0); + dptr = (struct dos_partition *)(((char *)0)+DOSPARTOFF); + for (i = 0; i < NDOSPART; i++, dptr++) + if (dptr->dp_typ == DOSPTYP_386BSD) + break; + sector = dptr->dp_start + LABELSECTOR; + Bread(dosdev, sector++); + dl=((struct disklabel *)0); + disklabel = *dl; /* structure copy (maybe useful later)*/ +#endif EMBEDDED_DISKLABEL + if (dl->d_magic != DISKMAGIC) { + printf("bad disklabel"); + return 1; + } + if( (maj == 4) || (maj == 0) || (maj == 1)) + { + if (dl->d_type == DTYPE_SCSI) + { + maj = 4; /* use scsi as boot dev */ + } + else + { + maj = 0; /* must be ESDI/IDE */ + } + } + boff = dl->d_partitions[part].p_offset; +#ifdef DO_BAD144 + bsize = dl->d_partitions[part].p_size; + do_bad144 = 0; + if (dl->d_flags & D_BADSECT) { + /* this disk uses bad144 */ + int i; + int dkbbnum; + struct dkbad *dkbptr; + + /* find the first readable bad144 sector */ + /* some of this code is copied from ufs/disk_subr.c */ + /* read a bad sector table */ + dkbbnum = dl->d_secperunit - dl->d_nsectors; + if (dl->d_secsize > DEV_BSIZE) + dkbbnum *= dl->d_secsize / DEV_BSIZE; + else + dkbbnum /= DEV_BSIZE / dl->d_secsize; + i = 0; + do_bad144 = 0; + do { + /* XXX: what if the "DOS sector" < 512 bytes ??? */ + Bread(dosdev, dkbbnum + i); + dkbptr = (struct dkbad *) 0; +/* XXX why is this not in <sys/dkbad.h> ??? */ +#define DKBAD_MAGIC 0x4321 + if (dkbptr->bt_mbz == 0 && + dkbptr->bt_flag == DKBAD_MAGIC) { + dkb = *dkbptr; /* structure copy */ + do_bad144 = 1; + break; + } + i += 2; + } while (i < 10 && i < dl->d_nsectors); + if (!do_bad144) + printf("Bad badsect table\n"); + else + printf("Using bad144 bad sector at %d\n", dkbbnum+i); + } +#endif DO_BAD144 + } + return 0; +} + +devread() +{ + int offset, sector = bnum; + int dosdev = inode.i_dev; + for (offset = 0; offset < cnt; offset += BPS) + { + Bread(dosdev, badsect(dosdev, sector++)); + bcopy(0, iodest+offset, BPS); + } +} + +Bread(dosdev,sector) + int dosdev,sector; +{ + int cyl = sector/spc, head = (sector%spc)/spt, secnum = sector%spt; + while (biosread(dosdev, cyl,head,secnum)) + { + printf("Error: C:%d H:%d S:%d\n",cyl,head,secnum); + } +} + +badsect(dosdev, sector) + int dosdev, sector; +{ + int i; +#ifdef DO_BAD144 + if (do_bad144) { + u_short cyl; + u_short head; + u_short sec; + int newsec; + struct disklabel *dl = &disklabel; + + /* XXX */ + /* from wd.c */ + /* bt_cyl = cylinder number in sorted order */ + /* bt_trksec is actually (head << 8) + sec */ + + /* only remap sectors in the partition */ + if (sector < boff || sector >= boff + bsize) { + goto no_remap; + } + + cyl = sector / dl->d_secpercyl; + head = (sector % dl->d_secpercyl) / dl->d_nsectors; + sec = sector % dl->d_nsectors; + sec = (head<<8) + sec; + + /* now, look in the table for a possible bad sector */ + for (i=0; i<126; i++) { + if (dkb.bt_bad[i].bt_cyl == cyl) { + /* found same cylinder */ + if (dkb.bt_bad[i].bt_trksec == sec) { + /* FOUND! */ + break; + } + } else if (dkb.bt_bad[i].bt_cyl > cyl) { + i = 126; + break; + } + } + if (i == 126) { + /* didn't find bad sector */ + goto no_remap; + } + /* otherwise find replacement sector */ + newsec = dl->d_secperunit - dl->d_nsectors - i -1; + return newsec; + } +#endif DO_BAD144 + no_remap: + return sector; +} diff --git a/sys/i386/boot/biosboot/io.c b/sys/i386/boot/biosboot/io.c new file mode 100644 index 000000000000..237b21cc2cf0 --- /dev/null +++ b/sys/i386/boot/biosboot/io.c @@ -0,0 +1,189 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: io.c,v $ + * Revision 2.2 92/04/04 11:35:57 rpd + * Fixed for IBM L40's A20 initialization. + * [92/03/30 rvb] + * + * Created. + * [92/03/30 mg32] + * + */ + +#include <i386/include/pio.h> + +#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ +#define K_STATUS 0x64 /* keyboard status */ +#define K_CMD 0x64 /* keybd ctlr command (write-only) */ + +#define K_OBUF_FUL 0x01 /* output buffer full */ +#define K_IBUF_FUL 0x02 /* input buffer full */ + +#define KC_CMD_WIN 0xd0 /* read output port */ +#define KC_CMD_WOUT 0xd1 /* write output port */ +#define KB_A20 0x9f /* enable A20, + enable output buffer full interrupt + enable data line + disable clock line */ + +/* + * Gate A20 for high memory + */ +unsigned char x_20 = KB_A20; +gateA20() +{ +#ifdef IBM_L40 + outb(0x92, 0x2); +#else IBM_L40 + while (inb(K_STATUS) & K_IBUF_FUL); + while (inb(K_STATUS) & K_OBUF_FUL) + (void)inb(K_RDWR); + + outb(K_CMD, KC_CMD_WOUT); + while (inb(K_STATUS) & K_IBUF_FUL); + outb(K_RDWR, x_20); + while (inb(K_STATUS) & K_IBUF_FUL); +#endif IBM_L40 +} + +/* printf - only handles %d as decimal, %c as char, %s as string */ + +printf(format,data) + char *format; + int data; +{ + int *dataptr = &data; + char c; + while (c = *format++) + if (c != '%') + putchar(c); + else + switch (c = *format++) { + case 'd': { + int num = *dataptr++; + char buf[10], *ptr = buf; + if (num<0) { + num = -num; + putchar('-'); + } + do + *ptr++ = '0'+num%10; + while (num /= 10); + do + putchar(*--ptr); + while (ptr != buf); + break; + } + case 'x': { + int num = *dataptr++, dig; + char buf[8], *ptr = buf; + do + *ptr++ = (dig=(num&0xf)) > 9? + 'a' + dig - 10 : + '0' + dig; + while (num >>= 4); + do + putchar(*--ptr); + while (ptr != buf); + break; + } + case 'c': putchar((*dataptr++)&0xff); break; + case 's': { + char *ptr = (char *)*dataptr++; + while (c = *ptr++) + putchar(c); + break; + } + } +} + +putchar(c) +{ + if (c == '\n') + putc('\r'); + putc(c); +} + +getchar() +{ + int c; + + if ((c=getc()) == '\r') + c = '\n'; + if (c == '\b') { + putchar('\b'); + putchar(' '); + } + putchar(c); + return(c); +} + +gets(buf) +char *buf; +{ + int i; + char *ptr=buf; + + for (i = 240000; i>0; i--) + if (ischar()) + for (;;) + switch(*ptr = getchar() & 0xff) { + case '\n': + case '\r': + *ptr = '\0'; + return 1; + case '\b': + if (ptr > buf) ptr--; + continue; + default: + ptr++; + } + return 0; +} + +strcmp(s1, s2) +char *s1, *s2; +{ + while (*s1 == *s2) { + if (!*s1++) + return 0; + s2++; + } + return 1; +} + +bcopy(from, to, len) +char *from, *to; +int len; +{ + while (len-- > 0) + *to++ = *from++; +} diff --git a/sys/i386/boot/biosboot/sys.c b/sys/i386/boot/biosboot/sys.c new file mode 100644 index 000000000000..bb34340da482 --- /dev/null +++ b/sys/i386/boot/biosboot/sys.c @@ -0,0 +1,240 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: sys.c,v $ + * Revision 2.2 92/04/04 11:36:34 rpd + * Fabricated from 3.0 bootstrap and scratch. + * [92/03/30 mg32] + * + */ + +#include "boot.h" +#include <sys/dir.h> +#include <sys/reboot.h> + +/* #define BUFSIZE 4096 */ +#define BUFSIZE MAXBSIZE + +char buf[BUFSIZE], fsbuf[SBSIZE], iobuf[MAXBSIZE]; + +int xread(addr, size) + char * addr; + int size; +{ + int count = BUFSIZE; + while (size > 0) { + if (BUFSIZE > size) + count = size; + read(buf, count); + pcpy(buf, addr, count); + size -= count; + addr += count; + } +} + +read(buffer, count) + int count; + char *buffer; +{ + int logno, off, size; + int cnt2, bnum2; + + while (count) { + off = blkoff(fs, poff); + logno = lblkno(fs, poff); + cnt2 = size = blksize(fs, &inode, logno); + bnum2 = fsbtodb(fs, block_map(logno)) + boff; + cnt = cnt2; + bnum = bnum2; + if ( (!off) && (size <= count)) + { + iodest = buffer; + devread(); + } + else + { + iodest = iobuf; + size -= off; + if (size > count) + size = count; + devread(); + bcopy(iodest+off,buffer,size); + } + buffer += size; + count -= size; + poff += size; + } +} + +find(path) + char *path; +{ + char *rest, ch; + int block, off, loc, ino = ROOTINO; + struct direct *dp; +loop: iodest = iobuf; + cnt = fs->fs_bsize; + bnum = fsbtodb(fs,itod(fs,ino)) + boff; + devread(); + bcopy(&((struct dinode *)iodest)[ino % fs->fs_inopb], + &inode.i_din, + sizeof (struct dinode)); + if (!*path) + return 1; + while (*path == '/') + path++; + if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR)) + return 0; + for (rest = path; (ch = *rest) && ch != '/'; rest++) ; + *rest = 0; + loc = 0; + do { + if (loc >= inode.i_size) + return 0; + if (!(off = blkoff(fs, loc))) { + block = lblkno(fs, loc); + cnt = blksize(fs, &inode, block); + bnum = fsbtodb(fs, block_map(block)) + boff; + iodest = iobuf; + devread(); + } + dp = (struct direct *)(iodest + off); + loc += dp->d_reclen; + } while (!dp->d_ino || strcmp(path, dp->d_name)); + ino = dp->d_ino; + *(path = rest) = ch; + goto loop; +} + +char mapbuf[MAXBSIZE]; +int mapblock = 0; + +block_map(file_block) + int file_block; +{ + if (file_block < NDADDR) + return(inode.i_db[file_block]); + if ((bnum=fsbtodb(fs, inode.i_ib[0])+boff) != mapblock) { + iodest = mapbuf; + cnt = fs->fs_bsize; + devread(); + mapblock = bnum; + } + return (((int *)mapbuf)[(file_block - NDADDR) % NINDIR(fs)]); +} + +openrd() +{ + char **devp, *cp = name; + /*******************************************************\ + * If bracket given look for preceding device name * + \*******************************************************/ + while (*cp && *cp!='(') + cp++; + if (!*cp) + { + cp = name; + } + else + { + if (cp++ != name) + { + for (devp = devs; *devp; devp++) + if (name[0] == (*devp)[0] && + name[1] == (*devp)[1]) + break; + if (!*devp) + { + printf("Unknown device\n"); + return 1; + } + maj = devp-devs; + } + /*******************************************************\ + * Look inside brackets for unit number, and partition * + \*******************************************************/ + if (*cp >= '0' && *cp <= '9') + if ((unit = *cp++ - '0') > 1) + { + printf("Bad unit\n"); + return 1; + } + if (!*cp || (*cp == ',' && !*++cp)) + return 1; + if (*cp >= 'a' && *cp <= 'p') + part = *cp++ - 'a'; + while (*cp && *cp++!=')') ; + if (!*cp) + return 1; + } + switch(maj) + { + case 1: + dosdev = unit | 0x80; + unit = 0; + break; + case 0: + case 4: + dosdev = unit | 0x80; + break; + case 2: + dosdev = unit; + break; + case 3: + printf("Wangtek unsupported\n"); + return 1; + break; + } + inode.i_dev = dosdev; + /***********************************************\ + * Now we know the disk unit and part, * + * Load disk info, (open the device) * + \***********************************************/ + if (devopen()) + return 1; + + /***********************************************\ + * Load Filesystem info (mount the device) * + \***********************************************/ + iodest = (char *)(fs = (struct fs *)fsbuf); + cnt = SBSIZE; + bnum = SBLOCK + boff; + devread(); + /***********************************************\ + * Find the actual FILE on the mounted device * + \***********************************************/ + if (!find(cp)) + { + return 1; + } + poff = 0; + name = cp; + return 0; +} diff --git a/sys/i386/boot/biosboot/table.c b/sys/i386/boot/biosboot/table.c new file mode 100644 index 000000000000..c26490ad0643 --- /dev/null +++ b/sys/i386/boot/biosboot/table.c @@ -0,0 +1,112 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: table.c,v $ + * Revision 2.2 92/04/04 11:36:43 rpd + * Fix Intel Copyright as per B. Davies authorization. + * [92/04/03 rvb] + * Taken from 2.5 bootstrap. + * [92/03/30 rvb] + * + * Revision 2.2 91/04/02 14:42:22 mbj + * Add Intel copyright + * [90/02/09 rvb] + * + */ + +/* + Copyright 1988, 1989, 1990, 1991, 1992 + 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. +*/ + +#define NGDTENT 6 +#define GDTLIMIT 48 /* NGDTENT * 8 */ + +/* Segment Descriptor + * + * 31 24 19 16 7 0 + * ------------------------------------------------------------ + * | | |B| |A| | | |1|0|E|W|A| | + * | BASE 31..24 |G|/|0|V| LIMIT |P|DPL| TYPE | BASE 23:16 | + * | | |D| |L| 19..16| | |1|1|C|R|A| | + * ------------------------------------------------------------ + * | | | + * | BASE 15..0 | LIMIT 15..0 | + * | | | + * ------------------------------------------------------------ + */ + +struct seg_desc { + unsigned short limit_15_0; + unsigned short base_15_0; + unsigned char base_23_16; + unsigned char bit_15_8; + unsigned char bit_23_16; + unsigned char base_31_24; + }; + + +struct seg_desc Gdt[NGDTENT] = { + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 0x0 : null */ + {0xFFFF, 0x0, 0x0, 0x9F, 0xCF, 0x0}, /* 0x08 : kernel code */ + {0xFFFF, 0x0, 0x0, 0x93, 0xCF, 0x0}, /* 0x10 : kernel data */ + {0xFFFF, 0x0000, 0x9, 0x9E, 0x40, 0x0}, /* 0x18 : boot code */ + {0xFFFF, 0x0000, 0x9, 0x92, 0x40, 0x0}, /* 0x20 : boot data */ + {0xFFFF, 0x0000, 0x9, 0x9E, 0x0, 0x0} /* 0x28 : boot code, 16 bits */ + }; + + +struct pseudo_desc { + unsigned short limit; + unsigned short base_low; + unsigned short base_high; + }; + +struct pseudo_desc Gdtr = { GDTLIMIT, 0x0400, 9 }; +struct pseudo_desc Gdtr2 = { GDTLIMIT, 0xfe00, 9 }; + /* boot is loaded at 0x90000, Gdt is at boot+1024 */ diff --git a/sys/i386/boot/boot.c b/sys/i386/boot/boot.c new file mode 100644 index 000000000000..805303e6dab2 --- /dev/null +++ b/sys/i386/boot/boot.c @@ -0,0 +1,323 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00159 + * -------------------- ----- ---------------------- + * + * 23 May 93 Rodney W. Grimes Added pad to kernel size for structs + * allocated by locore.s + */ + +/* + * HISTORY + * $Log: boot.c,v $ + * Revision 2.2 92/04/04 11:34:37 rpd + * Change date in banner. + * [92/04/03 16:51:14 rvb] + * + * Fix Intel Copyright as per B. Davies authorization. + * [92/04/03 rvb] + * From 2.5 version. + * [92/03/30 mg32] + * + */ + +/* + Copyright 1988, 1989, 1990, 1991, 1992 + 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 "boot.h" +#include <a.out.h> +#include <sys/reboot.h> + + +struct exec head; +int argv[10], esym; +char *name; +char *names[] = { + "/386bsd", "/386bsd.old", + "/vmunix", "/vmunix.old" +}; +#define NUMNAMES (sizeof(names)/sizeof(char *)) + +extern int end; +boot(drive) +int drive; +{ + int loadflags, currname = 0; + printf("\n>> 386bsd BOOT @ 0x%x: %d/%d k of memory [20/9/92]\n", + ouraddr, + argv[7] = memsize(0), + argv[8] = memsize(1)); + printf("use options hd(1,...... to boot sd0 when wd0 is also installed\n"); + gateA20(); +loadstart: + /***************************************************************\ + * As a default set it to the first partition of the first * + * floppy or hard drive * + \***************************************************************/ + part = unit = 0; + maj = (drive&0x80 ? 0 : 2); /* a good first bet */ + name = names[currname++]; + + loadflags = 0; + if (currname == NUMNAMES) + currname = 0; + getbootdev(&loadflags); + if (openrd()) { + printf("Can't find %s\n", name); + goto loadstart; + } +/* if (inode.i_mode&IEXEC) + loadflags |= RB_KDB; +*/ + loadprog(loadflags); + goto loadstart; +} + +loadprog(howto) + int howto; +{ + long int startaddr; + long int addr; /* physical address.. not directly useable */ + int i; + static int (*x_entry)() = 0; + unsigned char tmpbuf[4096]; /* we need to load the first 4k here */ + + argv[3] = 0; + argv[4] = 0; + read(&head, sizeof(head)); + if (head.a_magic == 0413 ) + { + poff = 4096; + } + else + { + printf("Invalid format!\n"); + return; + } + + startaddr = (int)head.a_entry; + addr = (startaddr & 0x00f00000); /* some MEG boundary */ + printf("Booting %s(%d,%c)%s @ 0x%x\n" + , devs[maj] + , unit + , 'a'+part + , name + , addr); + if(addr < ouraddr) + { + if((addr + head.a_text + head.a_data) > ouraddr) + { + printf("kernel will not fit below loader\n"); + return; + } + /* + * The +28672 is for memory allocated by locore.s that must + * fit in the bss! + */ + if((addr + head.a_text + head.a_data + head.a_bss + 28672) > 0xa0000) + { + printf("kernel too big, won't fit in 640K with bss\n"); + printf("Only hope is to link the kernel for > 1MB\n"); + return; + } + if((addr + head.a_text + head.a_data + head.a_bss) > ouraddr) + { + printf("loader overlaps bss, kernel must bzero\n"); + } + } + printf("text=0x%x", head.a_text); + /********************************************************/ + /* LOAD THE TEXT SEGMENT */ + /* don't clobber the first 4k yet (BIOS NEEDS IT) */ + /********************************************************/ + read(tmpbuf,4096); + addr += 4096; + xread(addr, head.a_text - 4096); + addr += head.a_text - 4096; + + /********************************************************/ + /* Load the Initialised data after the text */ + /********************************************************/ + while (addr & CLOFSET) + *(char *)addr++ = 0; + + printf(" data=0x%x", head.a_data); + xread(addr, head.a_data); + addr += head.a_data; + + /********************************************************/ + /* Skip over the uninitialised data */ + /* (but clear it) */ + /********************************************************/ + printf(" bss=0x%x", head.a_bss); + if( (addr < ouraddr) && ((addr + head.a_bss) > ouraddr)) + { + pbzero(addr,ouraddr - (int)addr); + } + else + { + pbzero(addr,head.a_bss); + } + argv[3] = (addr += head.a_bss); + +#ifdef LOADSYMS /* not yet, haven't worked this out yet */ + if (addr > 0x100000) + { + /********************************************************/ + /*copy in the symbol header */ + /********************************************************/ + pcpy(&head.a_syms, addr, sizeof(head.a_syms)); + addr += sizeof(head.a_syms); + + /********************************************************/ + /* READ in the symbol table */ + /********************************************************/ + printf(" symbols=[+0x%x", head.a_syms); + xread(addr, head.a_syms); + addr += head.a_syms; + + /********************************************************/ + /* Followed by the next integer (another header) */ + /* more debug symbols? */ + /********************************************************/ + read(&i, sizeof(int)); + pcpy(&i, addr, sizeof(int)); + i -= sizeof(int); + addr += sizeof(int); + + + /********************************************************/ + /* and that many bytes of (debug symbols?) */ + /********************************************************/ + printf("+0x%x]", i); + xread(addr, i); + addr += i; + } +#endif LOADSYMS + /********************************************************/ + /* and note the end address of all this */ + /********************************************************/ + + argv[4] = ((addr+sizeof(int)-1))&~(sizeof(int)-1); + printf(" total=0x%x",argv[4]); + + + /* + * We now pass the various bootstrap parameters to the loaded + * image via the argument list + * (THIS IS A BIT OF HISTORY FROM MACH.. LEAVE FOR NOW) + * arg1 = boot flags + * arg2 = boot device + * arg3 = start of symbol table (0 if not loaded) + * arg4 = end of symbol table (0 if not loaded) + * arg5 = transfer address from image + * arg6 = transfer address for next image pointer + */ + switch(maj) + { + case 2: + printf("\n\nInsert file system floppy \n"); + getchar(); + break; + case 4: + break; + } + argv[1] = howto; + argv[2] = (MAKEBOOTDEV(maj, 0, 0, unit, part)) ; + argv[5] = (head.a_entry &= 0xfffffff); + argv[6] = (int) &x_entry; + argv[0] = 8; + /****************************************************************/ + /* copy that first page and overwrite any BIOS variables */ + /****************************************************************/ + printf(" entry point=0x%x \n" ,((int)startaddr) & 0xffffff); + pcpy(tmpbuf, 0, 4096); + startprog(((int)startaddr & 0xffffff),argv); +} + +char namebuf[100]; +getbootdev(howto) + int *howto; +{ + char c, *ptr = namebuf; + printf("Boot: [[[%s(%d,%c)]%s][-s][-a][-d]] :- " + , devs[maj] + , unit + , 'a'+part + , name); + if (gets(namebuf)) { + while (c=*ptr) { + while (c==' ') + c = *++ptr; + if (!c) + return; + if (c=='-') + while ((c = *++ptr) && c!=' ') + switch (c) { + case 'a': + *howto |= RB_ASKNAME; continue; + case 's': + *howto |= RB_SINGLE; continue; + case 'd': + *howto |= RB_KDB; continue; + case 'b': + *howto |= RB_HALT; continue; + } + else { + name = ptr; + while ((c = *++ptr) && c!=' '); + if (c) + *ptr++ = 0; + } + } + } +} + diff --git a/sys/i386/boot/boot.h b/sys/i386/boot/boot.h new file mode 100644 index 000000000000..28a7a220e52c --- /dev/null +++ b/sys/i386/boot/boot.h @@ -0,0 +1,48 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: boot.h,v $ + * Revision 2.2 92/04/04 11:35:03 rpd + * Fabricated from 3.0 bootstrap. But too many things are global. + * [92/03/30 mg32] + * + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <ufs/quota.h> +#include <ufs/fs.h> +#include <ufs/inode.h> + +extern char *devs[], *name, *iodest; +extern struct fs *fs; +extern struct inode inode; +extern int dosdev, unit, part, maj, boff, poff, bnum, cnt; +extern long int ouraddr; diff --git a/sys/i386/boot/boot.sed b/sys/i386/boot/boot.sed new file mode 100644 index 000000000000..c6b38eaac732 --- /dev/null +++ b/sys/i386/boot/boot.sed @@ -0,0 +1,3 @@ +/^[ ]*.data/c\ + .text +/^[ ]*.ident/d diff --git a/sys/i386/boot/boot2.s b/sys/i386/boot/boot2.s new file mode 100644 index 000000000000..d319edf6d2d1 --- /dev/null +++ b/sys/i386/boot/boot2.s @@ -0,0 +1,73 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: boot2.s,v $ + * Revision 2.2 92/04/04 11:35:26 rpd + * From 2.5 + * [92/03/30 rvb] + * + * Revision 2.2 91/04/02 14:39:21 mbj + * Put into rcs tree + * [90/02/09 rvb] + * + */ + +#include "asm.h" +#define LOADMSG 1 +/* + * boot2() -- second stage boot + */ + +.globl _ouraddr + +ENTRY(boot2) + movl %cs, %ax + movl %ax, %ds + movl %ax, %es + data32 + sall $4, %eax + data32 + movl %eax, _ouraddr + /* save the drive type and ID */ + data32 + pushl %edx + /* change to protected mode */ + data32 + call _real_to_prot + + call _boot + ret + + .data + .align 2 +_ouraddr: + .long 0 + + diff --git a/sys/i386/boot/disk.c b/sys/i386/boot/disk.c new file mode 100644 index 000000000000..87b30b27fc2c --- /dev/null +++ b/sys/i386/boot/disk.c @@ -0,0 +1,238 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: disk.c,v $ + * Revision 2.2 92/04/04 11:35:49 rpd + * Fabricated from 3.0 bootstrap and 2.5 boot disk.c: + * with support for scsi + * [92/03/30 mg32] + * + */ + +/* + * 9/20/92 + * Peng-Toh Sim. sim@cory.berkeley.edu + * Added bad144 support under 386bsd for wd's + * So, bad block remapping is done when loading the kernel. + */ + +#include "boot.h" +#ifdef DO_BAD144 +#include <sys/dkbad.h> +#endif DO_BAD144 +#include <sys/disklabel.h> + +#define BIOS_DEV_FLOPPY 0x0 +#define BIOS_DEV_WIN 0x80 + +#define BPS 512 +#define SPT(di) ((di)&0xff) +#define HEADS(di) ((((di)>>8)&0xff)+1) + +char *devs[] = {"wd", "hd", "fd", "wt", "sd", 0}; + +#ifdef DO_BAD144 +struct dkbad dkb; +int do_bad144; +int bsize; +#endif DO_BAD144 + +int spt, spc; + +char *iodest; +struct fs *fs; +struct inode inode; +int dosdev, unit, part, maj, boff, poff, bnum, cnt; + +/*#define EMBEDDED_DISKLABEL 1*/ +extern struct disklabel disklabel; +/*struct disklabel disklabel;*/ + +devopen() +{ + struct dos_partition *dptr; + struct disklabel *dl; + int dosdev = inode.i_dev; + int i, sector, di; + + di = get_diskinfo(dosdev); + spc = (spt = SPT(di)) * HEADS(di); + if (dosdev == 2) + { + boff = 0; + part = (spt == 15 ? 3 : 1); + } + else + { +#ifdef EMBEDDED_DISKLABEL + dl = &disklabel; +#else EMBEDDED_DISKLABEL + Bread(dosdev, 0); + dptr = (struct dos_partition *)(((char *)0)+DOSPARTOFF); + for (i = 0; i < NDOSPART; i++, dptr++) + if (dptr->dp_typ == DOSPTYP_386BSD) + break; + sector = dptr->dp_start + LABELSECTOR; + Bread(dosdev, sector++); + dl=((struct disklabel *)0); + disklabel = *dl; /* structure copy (maybe useful later)*/ +#endif EMBEDDED_DISKLABEL + if (dl->d_magic != DISKMAGIC) { + printf("bad disklabel"); + return 1; + } + if( (maj == 4) || (maj == 0) || (maj == 1)) + { + if (dl->d_type == DTYPE_SCSI) + { + maj = 4; /* use scsi as boot dev */ + } + else + { + maj = 0; /* must be ESDI/IDE */ + } + } + boff = dl->d_partitions[part].p_offset; +#ifdef DO_BAD144 + bsize = dl->d_partitions[part].p_size; + do_bad144 = 0; + if (dl->d_flags & D_BADSECT) { + /* this disk uses bad144 */ + int i; + int dkbbnum; + struct dkbad *dkbptr; + + /* find the first readable bad144 sector */ + /* some of this code is copied from ufs/disk_subr.c */ + /* read a bad sector table */ + dkbbnum = dl->d_secperunit - dl->d_nsectors; + if (dl->d_secsize > DEV_BSIZE) + dkbbnum *= dl->d_secsize / DEV_BSIZE; + else + dkbbnum /= DEV_BSIZE / dl->d_secsize; + i = 0; + do_bad144 = 0; + do { + /* XXX: what if the "DOS sector" < 512 bytes ??? */ + Bread(dosdev, dkbbnum + i); + dkbptr = (struct dkbad *) 0; +/* XXX why is this not in <sys/dkbad.h> ??? */ +#define DKBAD_MAGIC 0x4321 + if (dkbptr->bt_mbz == 0 && + dkbptr->bt_flag == DKBAD_MAGIC) { + dkb = *dkbptr; /* structure copy */ + do_bad144 = 1; + break; + } + i += 2; + } while (i < 10 && i < dl->d_nsectors); + if (!do_bad144) + printf("Bad badsect table\n"); + else + printf("Using bad144 bad sector at %d\n", dkbbnum+i); + } +#endif DO_BAD144 + } + return 0; +} + +devread() +{ + int offset, sector = bnum; + int dosdev = inode.i_dev; + for (offset = 0; offset < cnt; offset += BPS) + { + Bread(dosdev, badsect(dosdev, sector++)); + bcopy(0, iodest+offset, BPS); + } +} + +Bread(dosdev,sector) + int dosdev,sector; +{ + int cyl = sector/spc, head = (sector%spc)/spt, secnum = sector%spt; + while (biosread(dosdev, cyl,head,secnum)) + { + printf("Error: C:%d H:%d S:%d\n",cyl,head,secnum); + } +} + +badsect(dosdev, sector) + int dosdev, sector; +{ + int i; +#ifdef DO_BAD144 + if (do_bad144) { + u_short cyl; + u_short head; + u_short sec; + int newsec; + struct disklabel *dl = &disklabel; + + /* XXX */ + /* from wd.c */ + /* bt_cyl = cylinder number in sorted order */ + /* bt_trksec is actually (head << 8) + sec */ + + /* only remap sectors in the partition */ + if (sector < boff || sector >= boff + bsize) { + goto no_remap; + } + + cyl = sector / dl->d_secpercyl; + head = (sector % dl->d_secpercyl) / dl->d_nsectors; + sec = sector % dl->d_nsectors; + sec = (head<<8) + sec; + + /* now, look in the table for a possible bad sector */ + for (i=0; i<126; i++) { + if (dkb.bt_bad[i].bt_cyl == cyl) { + /* found same cylinder */ + if (dkb.bt_bad[i].bt_trksec == sec) { + /* FOUND! */ + break; + } + } else if (dkb.bt_bad[i].bt_cyl > cyl) { + i = 126; + break; + } + } + if (i == 126) { + /* didn't find bad sector */ + goto no_remap; + } + /* otherwise find replacement sector */ + newsec = dl->d_secperunit - dl->d_nsectors - i -1; + return newsec; + } +#endif DO_BAD144 + no_remap: + return sector; +} diff --git a/sys/i386/boot/io.c b/sys/i386/boot/io.c new file mode 100644 index 000000000000..237b21cc2cf0 --- /dev/null +++ b/sys/i386/boot/io.c @@ -0,0 +1,189 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: io.c,v $ + * Revision 2.2 92/04/04 11:35:57 rpd + * Fixed for IBM L40's A20 initialization. + * [92/03/30 rvb] + * + * Created. + * [92/03/30 mg32] + * + */ + +#include <i386/include/pio.h> + +#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ +#define K_STATUS 0x64 /* keyboard status */ +#define K_CMD 0x64 /* keybd ctlr command (write-only) */ + +#define K_OBUF_FUL 0x01 /* output buffer full */ +#define K_IBUF_FUL 0x02 /* input buffer full */ + +#define KC_CMD_WIN 0xd0 /* read output port */ +#define KC_CMD_WOUT 0xd1 /* write output port */ +#define KB_A20 0x9f /* enable A20, + enable output buffer full interrupt + enable data line + disable clock line */ + +/* + * Gate A20 for high memory + */ +unsigned char x_20 = KB_A20; +gateA20() +{ +#ifdef IBM_L40 + outb(0x92, 0x2); +#else IBM_L40 + while (inb(K_STATUS) & K_IBUF_FUL); + while (inb(K_STATUS) & K_OBUF_FUL) + (void)inb(K_RDWR); + + outb(K_CMD, KC_CMD_WOUT); + while (inb(K_STATUS) & K_IBUF_FUL); + outb(K_RDWR, x_20); + while (inb(K_STATUS) & K_IBUF_FUL); +#endif IBM_L40 +} + +/* printf - only handles %d as decimal, %c as char, %s as string */ + +printf(format,data) + char *format; + int data; +{ + int *dataptr = &data; + char c; + while (c = *format++) + if (c != '%') + putchar(c); + else + switch (c = *format++) { + case 'd': { + int num = *dataptr++; + char buf[10], *ptr = buf; + if (num<0) { + num = -num; + putchar('-'); + } + do + *ptr++ = '0'+num%10; + while (num /= 10); + do + putchar(*--ptr); + while (ptr != buf); + break; + } + case 'x': { + int num = *dataptr++, dig; + char buf[8], *ptr = buf; + do + *ptr++ = (dig=(num&0xf)) > 9? + 'a' + dig - 10 : + '0' + dig; + while (num >>= 4); + do + putchar(*--ptr); + while (ptr != buf); + break; + } + case 'c': putchar((*dataptr++)&0xff); break; + case 's': { + char *ptr = (char *)*dataptr++; + while (c = *ptr++) + putchar(c); + break; + } + } +} + +putchar(c) +{ + if (c == '\n') + putc('\r'); + putc(c); +} + +getchar() +{ + int c; + + if ((c=getc()) == '\r') + c = '\n'; + if (c == '\b') { + putchar('\b'); + putchar(' '); + } + putchar(c); + return(c); +} + +gets(buf) +char *buf; +{ + int i; + char *ptr=buf; + + for (i = 240000; i>0; i--) + if (ischar()) + for (;;) + switch(*ptr = getchar() & 0xff) { + case '\n': + case '\r': + *ptr = '\0'; + return 1; + case '\b': + if (ptr > buf) ptr--; + continue; + default: + ptr++; + } + return 0; +} + +strcmp(s1, s2) +char *s1, *s2; +{ + while (*s1 == *s2) { + if (!*s1++) + return 0; + s2++; + } + return 1; +} + +bcopy(from, to, len) +char *from, *to; +int len; +{ + while (len-- > 0) + *to++ = *from++; +} diff --git a/sys/i386/boot/rmaouthdr b/sys/i386/boot/rmaouthdr new file mode 100644 index 000000000000..d69d3917c1f4 --- /dev/null +++ b/sys/i386/boot/rmaouthdr @@ -0,0 +1,12 @@ +#!/bin/csh -f +# Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 +# +# +# HISTORY +# $Log: rmaouthdr,v $ +# Revision 2.2 92/04/04 11:36:01 rpd +# From 2.5 boot +# [92/03/30 mg32] +# +# +dd if=$1 of=$2 ibs=32 skip=1 obs=1024b diff --git a/sys/i386/boot/start.s b/sys/i386/boot/start.s new file mode 100644 index 000000000000..f6f4bf0e7d11 --- /dev/null +++ b/sys/i386/boot/start.s @@ -0,0 +1,323 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: start.s,v $ + * Revision 2.2 92/04/04 11:36:29 rpd + * Fix Intel Copyright as per B. Davies authorization. + * [92/04/03 rvb] + * Need to zero dh on hd path; at least for an adaptec card. + * [92/01/14 rvb] + * + * From 2.5 boot: + * Flush digit printing. + * Fuse floppy and hd boot by using Int 21 to tell + * boot type (slightly dubious since Int 21 is DOS + * not BIOS) + * [92/03/30 mg32] + * + * Revision 2.2 91/04/02 14:42:04 mbj + * Fix the BIG boot bug. We had missed a necessary data + * before a xor that was clearing a register used later + * as an index register. + * [91/03/01 rvb] + * Remember floppy type for swapgeneric + * Add Intel copyright + * [90/02/09 rvb] + * + */ + + +/* + Copyright 1988, 1989, 1990, 1991, 1992 + 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 "asm.h" + + .file "start.s" + +BOOTSEG = 0x9000 # boot will be loaded at 640k-64k +BOOTSTACK = 0xe000 # boot stack +SIGNATURE = 0xaa55 +LOADSZ = 14 # size of unix boot +PARTSTART = 0x1be # starting address of partition table +NUMPART = 4 # number of partitions in partition table +PARTSZ = 16 # each partition table entry is 16 bytes +BSDPART = 0xA5 # value of boot_ind, means bootable partition +BOOTABLE = 0x80 # value of boot_ind, means bootable partition + + .text + +ENTRY(boot1) + + # boot1 is loaded at 0x0:0x7c00 + # ljmp to the next instruction to set up %cs + data32 + ljmp $0x7c0, $start + +start: + # set up %ds + mov %cs, %ax + mov %ax, %ds + + + # set up %ss and %esp + data32 + mov $BOOTSEG, %eax + mov %ax, %ss + data32 + mov $BOOTSTACK, %esp + + /*** set up %es, (where we will load boot2 to) ***/ + mov %ax, %es + +#ifdef DEBUG + data32 + mov $one, %esi + data32 + call message +#endif + # get the boot drive id + movb $0x33, %ah + movb $0x05, %al + int $0x21 + + cmpb $0x80, %dl + data32 + jge hd + +fd: +# reset the disk system +#ifdef DEBUG + data32 + mov $two, %esi + data32 + call message +#endif + movb $0x0, %ah + int $0x13 + data32 + mov $0x0001, %ecx # cyl 0, sector 1 + data32 +#ifdef DEBUG + data32 + mov $three, %esi + data32 + call message +#endif + jmp load + +hd: /**** load sector 0 into the BOOTSEG ****/ +#ifdef DEBUG + data32 + mov $four, %esi + data32 + call message +#endif + data32 + mov $0x0201, %eax + xor %ebx, %ebx # %bx = 0 + data32 + mov $0x0001, %ecx +#ifdef DEBUG + data32 + mov $five, %esi + data32 + call message +#endif + data32 + andl $0xff, %edx + /*mov $0x0080, %edx*/ + int $0x13 + data32 + jb read_error + + /***# find the bootable partition *****/ + data32 + mov $PARTSTART, %ebx + data32 + mov $NUMPART, %ecx +again: + addr16 + movb %es:4(%ebx), %al + cmpb $BSDPART, %al + data32 + je found + data32 + add $PARTSZ, %ebx + data32 + loop again + data32 + mov $enoboot, %esi + data32 + jmp err_stop + + +/* +# BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory +# Call with %ah = 0x2 +# %al = number of sectors +# %ch = cylinder +# %cl = sector +# %dh = head +# %dl = drive (0x80 for hard disk, 0x0 for floppy disk) +# %es:%bx = segment:offset of buffer +# Return: +# %al = 0x0 on success; err code on failure +*/ + +found: + addr16 + movb %es:1(%ebx), %dh /* head */ + addr16 + xor %ecx, %ecx + addr16 + movw %es:2(%ebx), %ecx /*sect,cyl (+ 2 bytes junk in top word )*/ + +load: + movb $0x2, %ah /* function 2 */ + movb $LOADSZ, %al /* number of blocks */ + xor %ebx, %ebx /* %bx = 0, put it at 0 in the BOOTSEG */ + int $0x13 + data32 + jb read_error + + # ljmp to the second stage boot loader (boot2). + # After ljmp, %cs is BOOTSEG and boot1 (512 bytes) will be used + # as an internal buffer "intbuf". + +#ifdef DEBUG + data32 + mov $six, %esi + data32 + call message +#endif + data32 + ljmp $BOOTSEG, $EXT(boot2) + +# +# read_error +# + +read_error: + + data32 + mov $eread, %esi +err_stop: + data32 + call message + data32 + jmp stop + +# +# message: write the error message in %ds:%esi to console +# + +message: + # Use BIOS "int 10H Function 0Eh" to write character in teletype mode + # %ah = 0xe %al = character + # %bh = page %bl = foreground color (graphics modes) + + data32 + push %eax + data32 + push %ebx + data32 + mov $0x0001, %ebx + cld + +nextb: + lodsb # load a byte into %al + cmpb $0x0, %al + data32 + je done + movb $0xe, %ah + int $0x10 # display a byte + data32 + jmp nextb +done: + data32 + pop %ebx + data32 + pop %eax + data32 + ret + +stop: hlt + data32 + jmp stop # halt doesnt actually halt forever + +/* error messages */ + +#ifdef DEBUG +one: String "1\r\n\0" +two: String "2\r\n\0" +three: String "3\r\n\0" +four: String "4\r\n\0" +five: String "5\r\n\0" +six: String "6\r\n\0" +seven: String "7\r\n\0" +#endif DEBUG +eread: String "Read error\r\n\0" +enoboot: String "No bootable partition\r\n\0" +endofcode: +/* throw in a partition in case we are block0 as well */ +/* flag,head,sec,cyl,typ,ehead,esect,ecyl,start,len */ + . = EXT(boot1) + PARTSTART + .byte 0x0,0,0,0,0,0,0,0 + .long 0,0 + .byte 0x0,0,0,0,0,0,0,0 + .long 0,0 + .byte 0x0,0,0,0,0,0,0,0 + .long 0,0 + .byte BOOTABLE,0,1,0,BSDPART,255,255,255 + .long 0,50000 +/* the last 2 bytes in the sector 0 contain the signature */ + . = EXT(boot1) + 0x1fe + .value SIGNATURE +ENTRY(disklabel) + . = EXT(boot1) + 0x400 diff --git a/sys/i386/boot/sys.c b/sys/i386/boot/sys.c new file mode 100644 index 000000000000..bb34340da482 --- /dev/null +++ b/sys/i386/boot/sys.c @@ -0,0 +1,240 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: sys.c,v $ + * Revision 2.2 92/04/04 11:36:34 rpd + * Fabricated from 3.0 bootstrap and scratch. + * [92/03/30 mg32] + * + */ + +#include "boot.h" +#include <sys/dir.h> +#include <sys/reboot.h> + +/* #define BUFSIZE 4096 */ +#define BUFSIZE MAXBSIZE + +char buf[BUFSIZE], fsbuf[SBSIZE], iobuf[MAXBSIZE]; + +int xread(addr, size) + char * addr; + int size; +{ + int count = BUFSIZE; + while (size > 0) { + if (BUFSIZE > size) + count = size; + read(buf, count); + pcpy(buf, addr, count); + size -= count; + addr += count; + } +} + +read(buffer, count) + int count; + char *buffer; +{ + int logno, off, size; + int cnt2, bnum2; + + while (count) { + off = blkoff(fs, poff); + logno = lblkno(fs, poff); + cnt2 = size = blksize(fs, &inode, logno); + bnum2 = fsbtodb(fs, block_map(logno)) + boff; + cnt = cnt2; + bnum = bnum2; + if ( (!off) && (size <= count)) + { + iodest = buffer; + devread(); + } + else + { + iodest = iobuf; + size -= off; + if (size > count) + size = count; + devread(); + bcopy(iodest+off,buffer,size); + } + buffer += size; + count -= size; + poff += size; + } +} + +find(path) + char *path; +{ + char *rest, ch; + int block, off, loc, ino = ROOTINO; + struct direct *dp; +loop: iodest = iobuf; + cnt = fs->fs_bsize; + bnum = fsbtodb(fs,itod(fs,ino)) + boff; + devread(); + bcopy(&((struct dinode *)iodest)[ino % fs->fs_inopb], + &inode.i_din, + sizeof (struct dinode)); + if (!*path) + return 1; + while (*path == '/') + path++; + if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR)) + return 0; + for (rest = path; (ch = *rest) && ch != '/'; rest++) ; + *rest = 0; + loc = 0; + do { + if (loc >= inode.i_size) + return 0; + if (!(off = blkoff(fs, loc))) { + block = lblkno(fs, loc); + cnt = blksize(fs, &inode, block); + bnum = fsbtodb(fs, block_map(block)) + boff; + iodest = iobuf; + devread(); + } + dp = (struct direct *)(iodest + off); + loc += dp->d_reclen; + } while (!dp->d_ino || strcmp(path, dp->d_name)); + ino = dp->d_ino; + *(path = rest) = ch; + goto loop; +} + +char mapbuf[MAXBSIZE]; +int mapblock = 0; + +block_map(file_block) + int file_block; +{ + if (file_block < NDADDR) + return(inode.i_db[file_block]); + if ((bnum=fsbtodb(fs, inode.i_ib[0])+boff) != mapblock) { + iodest = mapbuf; + cnt = fs->fs_bsize; + devread(); + mapblock = bnum; + } + return (((int *)mapbuf)[(file_block - NDADDR) % NINDIR(fs)]); +} + +openrd() +{ + char **devp, *cp = name; + /*******************************************************\ + * If bracket given look for preceding device name * + \*******************************************************/ + while (*cp && *cp!='(') + cp++; + if (!*cp) + { + cp = name; + } + else + { + if (cp++ != name) + { + for (devp = devs; *devp; devp++) + if (name[0] == (*devp)[0] && + name[1] == (*devp)[1]) + break; + if (!*devp) + { + printf("Unknown device\n"); + return 1; + } + maj = devp-devs; + } + /*******************************************************\ + * Look inside brackets for unit number, and partition * + \*******************************************************/ + if (*cp >= '0' && *cp <= '9') + if ((unit = *cp++ - '0') > 1) + { + printf("Bad unit\n"); + return 1; + } + if (!*cp || (*cp == ',' && !*++cp)) + return 1; + if (*cp >= 'a' && *cp <= 'p') + part = *cp++ - 'a'; + while (*cp && *cp++!=')') ; + if (!*cp) + return 1; + } + switch(maj) + { + case 1: + dosdev = unit | 0x80; + unit = 0; + break; + case 0: + case 4: + dosdev = unit | 0x80; + break; + case 2: + dosdev = unit; + break; + case 3: + printf("Wangtek unsupported\n"); + return 1; + break; + } + inode.i_dev = dosdev; + /***********************************************\ + * Now we know the disk unit and part, * + * Load disk info, (open the device) * + \***********************************************/ + if (devopen()) + return 1; + + /***********************************************\ + * Load Filesystem info (mount the device) * + \***********************************************/ + iodest = (char *)(fs = (struct fs *)fsbuf); + cnt = SBSIZE; + bnum = SBLOCK + boff; + devread(); + /***********************************************\ + * Find the actual FILE on the mounted device * + \***********************************************/ + if (!find(cp)) + { + return 1; + } + poff = 0; + name = cp; + return 0; +} diff --git a/sys/i386/boot/table.c b/sys/i386/boot/table.c new file mode 100644 index 000000000000..c26490ad0643 --- /dev/null +++ b/sys/i386/boot/table.c @@ -0,0 +1,112 @@ +/* + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 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. + */ + +/* + * HISTORY + * $Log: table.c,v $ + * Revision 2.2 92/04/04 11:36:43 rpd + * Fix Intel Copyright as per B. Davies authorization. + * [92/04/03 rvb] + * Taken from 2.5 bootstrap. + * [92/03/30 rvb] + * + * Revision 2.2 91/04/02 14:42:22 mbj + * Add Intel copyright + * [90/02/09 rvb] + * + */ + +/* + Copyright 1988, 1989, 1990, 1991, 1992 + 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. +*/ + +#define NGDTENT 6 +#define GDTLIMIT 48 /* NGDTENT * 8 */ + +/* Segment Descriptor + * + * 31 24 19 16 7 0 + * ------------------------------------------------------------ + * | | |B| |A| | | |1|0|E|W|A| | + * | BASE 31..24 |G|/|0|V| LIMIT |P|DPL| TYPE | BASE 23:16 | + * | | |D| |L| 19..16| | |1|1|C|R|A| | + * ------------------------------------------------------------ + * | | | + * | BASE 15..0 | LIMIT 15..0 | + * | | | + * ------------------------------------------------------------ + */ + +struct seg_desc { + unsigned short limit_15_0; + unsigned short base_15_0; + unsigned char base_23_16; + unsigned char bit_15_8; + unsigned char bit_23_16; + unsigned char base_31_24; + }; + + +struct seg_desc Gdt[NGDTENT] = { + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 0x0 : null */ + {0xFFFF, 0x0, 0x0, 0x9F, 0xCF, 0x0}, /* 0x08 : kernel code */ + {0xFFFF, 0x0, 0x0, 0x93, 0xCF, 0x0}, /* 0x10 : kernel data */ + {0xFFFF, 0x0000, 0x9, 0x9E, 0x40, 0x0}, /* 0x18 : boot code */ + {0xFFFF, 0x0000, 0x9, 0x92, 0x40, 0x0}, /* 0x20 : boot data */ + {0xFFFF, 0x0000, 0x9, 0x9E, 0x0, 0x0} /* 0x28 : boot code, 16 bits */ + }; + + +struct pseudo_desc { + unsigned short limit; + unsigned short base_low; + unsigned short base_high; + }; + +struct pseudo_desc Gdtr = { GDTLIMIT, 0x0400, 9 }; +struct pseudo_desc Gdtr2 = { GDTLIMIT, 0xfe00, 9 }; + /* boot is loaded at 0x90000, Gdt is at boot+1024 */ diff --git a/sys/i386/conf/GENERICAH b/sys/i386/conf/GENERICAH new file mode 100644 index 000000000000..5f8ed03c7e7c --- /dev/null +++ b/sys/i386/conf/GENERICAH @@ -0,0 +1,95 @@ +# +# GENERICISA -- Generic ISA machine -- distribution floppy +# +# +# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE +# -------------------- ----- ---------------------- +# CURRENT PATCH LEVEL: 3 00158 +# -------------------- ----- ---------------------- +# +# 09 Feb 93 Nate Williams Added options for X code to +# compiled in by default +# 29 Mar 93 Rodney W. Grimes Fixed com ports to be com0, com1 +# Added com2, com3, lpt, lpa +# Replaced as0 with Julian SCSI +# Fixed secound wd0 to be wd1 +# Cleaned up file, added comments +# Added ahb, order is important! +# Added pseudo-device speaker +# Note: All IO_xxx names are 1 based +# 17 May 93 Rodney W. Grimes Updated IRQ's 2 to IRQ 9's for +# intr-0.1 code. Changed ahb0 from +# irq 12 to irq 11 the real default +# + +machine "i386" +cpu "i386" +ident GENERICISA +timezone 8 dst +maxusers 10 +options INET #InterNETworking +options ISOFS #ISO File System +options NFS #Network File System +options "COMPAT_43" #Compatible with BSD 4.3 +options "TCP_COMPAT_42" #TCP/IP compatible with 4.2 +options XSERVER #Xserver +options UCONSOLE #X Console support + +config "386bsd" root on wd0 swap on wd0 and sd0 + +controller isa0 + +controller fd0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr +disk fd0 at fd0 drive 0 +disk fd1 at fd0 drive 1 + +controller wd0 at isa? port "IO_WD1" bio irq 14 vector wdintr +disk wd0 at wd0 drive 0 +disk wd1 at wd0 drive 1 + +controller ahb0 at isa? bio irq 11 vector ahbintr +controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr +controller scbus0 + +device sd0 +device sd1 +device sd2 +device sd3 + +device st0 +device st1 +device st2 +device st3 + +device cd0 +device cd1 + +device pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint +device npx0 at isa? port "IO_NPX" irq 13 vector npxintr + +device com0 at isa? port "IO_COM1" tty irq 4 vector comintr +device com1 at isa? port "IO_COM2" tty irq 3 vector comintr +device com2 at isa? port "IO_COM3" tty irq 5 vector comintr +device com3 at isa? port "IO_COM4" tty irq 9 vector comintr + +device lpt0 at isa? port "IO_LPT3" tty irq 7 vector lptintr +device lpa0 at isa? port "IO_LPT1" tty +device lpa1 at isa? port "IO_LPT2" tty + +device we0 at isa? port 0x280 net irq 9 iomem 0xd0000 iosiz 8192 vector weintr +device ne0 at isa? port 0x300 net irq 9 vector neintr +device ec0 at isa? port 0x250 net irq 9 iomem 0xd8000 iosiz 8192 vector ecintr +device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr + +device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr + +pseudo-device loop +pseudo-device ether +pseudo-device log +pseudo-device sl 2 +pseudo-device pty 4 +pseudo-device speaker + +pseudo-device swappager +pseudo-device vnodepager +pseudo-device devpager diff --git a/sys/i386/conf/Makefile.i386 b/sys/i386/conf/Makefile.i386 new file mode 100644 index 000000000000..7eedfb83b988 --- /dev/null +++ b/sys/i386/conf/Makefile.i386 @@ -0,0 +1,164 @@ +# Copyright 1990 W. Jolitz +# @(#)Makefile.i386 7.1 5/10/91 +# Makefile for 4.3 BSD-Reno +# +# This makefile is constructed from a machine description: +# config machineid +# Most changes should be made in the machine description +# /sys/i386/conf/``machineid'' +# after which you should do +# config machineid +# Generic makefile changes should be made in +# /sys/i386/conf/Makefile.i386 +# after which config should be rerun for all machines. +# +# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE INVISIBLE 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 +# +# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE +# -------------------- ----- ---------------------- +# CURRENT PATCH LEVEL: 3 00158 +# -------------------- ----- ---------------------- +# +# 29 Jun 92 Chris G. Demetriou Fix vers.o for kernel profiling and +# plain old link +# 25 Mar 93 Sean Eric Fagan Add support for assembler source +# 25 Apr 93 Bruce Evans Support for intr-0.0, and some fixes +# Rodney W. Grimes Added depedencies for conf.o due to +# all the new drivers. And to param.c +# because there were missing. +# 26 May 97 Rodney W. Grimes Remove extra SYSTEM_LD_TAIL +# Redirect stderr from dbsym to null, +# this is bad, but atleast I won't get +# 100's of bug reports about the silly +# warning from dbsym. +# +TOUCH= touch -f -c +LD= /usr/bin/ld +CC= cc +CPP= cpp + +S= ../.. +I386= ../../i386 + +INCLUDES= -I. -I$S -I$S/sys +COPTS= ${INCLUDES} ${IDENT} -DKERNEL -Di386 -DNPX +ASFLAGS= +CFLAGS= -O ${COPTS} + +NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} $< +NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $< +NORMAL_S= ${CPP} -I. -DLOCORE ${COPTS} $< | ${AS} ${ASFLAGS} -o $*.o +DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $< +DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $< +SYSTEM_OBJS=locore.o ${OBJS} param.o ioconf.o conf.o +SYSTEM_DEP=Makefile symbols.sort ${SYSTEM_OBJS} +SYSTEM_LD_HEAD= @echo loading $@; rm -f $@ +SYSTEM_LD= @${LD} -z -T FE000000 -o $@ -X vers.o ${SYSTEM_OBJS} +SYSTEM_LD_TAIL= @echo rearranging symbols; symorder symbols.sort $@; \ + dbsym $@ 2>/dev/null || true; size $@; chmod 755 $@ + +GPROF.EX= /usr/src/lib/csu.i386/gprof.ex +PROFILE_C= ${CC} -S -c ${CFLAGS} $< ; \ + ex - $*.s < ${GPROF.EX} ; \ + ${AS} -o $@ $*.s ; \ + rm -f $*.s + +%OBJS + +%CFILES + +%LOAD + +clean: + rm -f eddep *386bsd tags *.o locore.i [a-uw-z]*.s \ + errs linterrs makelinks genassym + +lint: /tmp param.c + @lint -hbxn -I. -DGENERIC -Dvolatile= ${COPTS} ${PARAM} \ + ${I386}/i386/Locore.c ${CFILES} ioconf.c param.c | \ + grep -v 'struct/union .* never defined' | \ + grep -v 'possible pointer alignment problem' + +symbols.sort: ${I386}/i386/symbols.raw + grep -v '^#' ${I386}/i386/symbols.raw \ + | sed 's/^ //' | sort -u > symbols.sort + +locore.o: assym.s ${I386}/i386/locore.s machine/trap.h machine/psl.h \ + machine/pte.h ${I386}/isa/vector.s ${I386}/isa/icu.s \ + $S/sys/errno.h machine/specialreg.h ${I386}/isa/debug.h \ + ${I386}/isa/icu.h ${I386}/isa/isa.h vector.h $S/net/netisr.h + ${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/locore.s | \ + ${AS} ${ASFLAGS} -o locore.o + +# the following is necessary because autoconf.o depends on #if GENERIC +autoconf.o: Makefile + +# depend on network configuration +af.o uipc_proto.o locore.o: Makefile + +# depend on maxusers +assym.s machdep.o: Makefile + +# depends on KDB (cons.o also depends on GENERIC) +trap.o cons.o: Makefile + +assym.s: $S/sys/param.h machine/pte.h $S/sys/buf.h \ + $S/sys/vmmeter.h \ + $S/sys/proc.h $S/sys/msgbuf.h machine/vmparam.h + +assym.s: genassym + ./genassym >assym.s + +genassym: + ${CC} ${INCLUDES} -DKERNEL ${IDENT} ${PARAM} \ + ${I386}/i386/genassym.c -o genassym + +depend: assym.s param.c + sh /usr/bin/mkdep ${COPTS} ${CFILES} ioconf.c + sh /usr/bin/mkdep -a -p ${INCLUDES} ${IDENT} ${PARAM} ${I386}/i386/genassym.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 $S/sys/param.h machine/pte.h $S/sys/buf.h \ + ${I386}/isa/isa_device.h ${I386}/isa/isa.h ${I386}/isa/icu.h + ${CC} -c ${CFLAGS} ioconf.c + +conf.o: $S/sys/param.h $S/sys/systm.h $S/sys/buf.h $S/sys/ioctl.h \ + $S/sys/tty.h $S/sys/conf.h \ + as.h bpfilter.h cd.h ch.h com.h dcfclk.h fd.h lpa.h \ + lpt.h pty.h sd.h speaker.h st.h wd.h wt.h \ + ${I386}/i386/conf.c + ${CC} -traditional -c ${CFLAGS} ${I386}/i386/conf.c + +param.c: $S/conf/param.c \ + $S/sys/param.h $S/sys/systm.h $S/sys/socket.h $S/sys/proc.h \ + $S/sys/vnode.h $S/sys/file.h $S/sys/callout.h $S/sys/clist.h \ + $S/sys/mbuf.h $S/ufs/quota.h $S/sys/kernel.h machine/vmparam.h \ + $S/sys/shm.h + -rm -f param.c + cp $S/conf/param.c . + +param.o: param.c Makefile + ${CC} -c ${CFLAGS} ${PARAM} param.c + +newvers: + sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT} + ${CC} ${CFLAGS} -c vers.c + +%RULES + +# DO NOT DELETE THIS LINE -- make depend uses it + diff --git a/sys/i386/conf/devices.i386 b/sys/i386/conf/devices.i386 new file mode 100644 index 000000000000..84f7affeb9b5 --- /dev/null +++ b/sys/i386/conf/devices.i386 @@ -0,0 +1,18 @@ +# This file tells what major numbers the various possible swap devices have. +# +# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE +# -------------------- ----- ---------------------- +# CURRENT PATCH LEVEL: 1 00097 +# -------------------- ----- ---------------------- +# +# 17 Feb 93 Julian Elischer Add devices for new scsi disks +# 10 Mar 93 Rodney W. Grimes Add more devices, st and cd +# +wd 0 +dk 1 +fd 2 +wt 3 +sd 4 +as 4 +st 5 +cd 6 diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386 new file mode 100644 index 000000000000..578472cc73d2 --- /dev/null +++ b/sys/i386/conf/files.i386 @@ -0,0 +1,71 @@ +# +# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE +# -------------------- ----- ---------------------- +# CURRENT PATCH LEVEL: 3 00160 +# -------------------- ----- ---------------------- +# +# 17 Feb 93 Julian Elischer Added files for scsi +# 10 Mar 93 Rodney W. Grimes Added files for lpt and lpa +# 25 Mar 93 Sean Eric Fagan Added microtime.s routine +# 08 Apr 93 Rodney W. Grimes Cleaned up the tabs, sorted file names +# Added ix, speaker, dcfclock +# 23 Apr 93 Holger Veit Added codrv +# 26 May 93 Rodney W. Grimes Rename of Bruce Evans com driver to sio +# Gene Stark Add xten power controler driver (tw) +# David Greenman Add ethernet driver (SMC/WD/3COM) (ed) +# Rick Macklem Add bus mouse driver (mse) +# +i386/i386/autoconf.c standard device-driver +i386/i386/cons.c standard +i386/i386/db_disasm.c optional ddb +i386/i386/db_interface.c optional ddb +i386/i386/db_trace.c optional ddb +i386/i386/in_cksum.c optional inet +i386/i386/machdep.c standard config-dependent +i386/i386/math_emulate.c standard +i386/i386/mem.c standard +i386/i386/microtime.s standard +i386/i386/ns_cksum.c optional ns +i386/i386/pmap.c standard +i386/i386/sys_machdep.c standard +i386/i386/trap.c standard +i386/i386/vm_machdep.c standard +i386/isa/aha1542.c optional aha device-driver +i386/isa/aha1742.c optional ahb device-driver +i386/isa/as.c optional as device-driver +i386/isa/bt742a.c optional bt device-driver +i386/isa/clock.c standard +i386/isa/codrv/co_cons.c optional co device-driver +i386/isa/codrv/co_kbd.c optional co device-driver +i386/isa/codrv/co_vga.c optional co device-driver +i386/isa/codrv/co_codrv1.c optional co device-driver +i386/isa/codrv/co_vty.c optional vty +i386/isa/codrv/co_pc3.c optional vtemul +i386/isa/codrv/co_mini.c optional vtemul +i386/isa/com.c optional com device-driver +i386/isa/dcfclk.c optional dcfclk device-driver +i386/isa/fd.c optional fd device-driver +i386/isa/if_ec.c optional ec device-driver +i386/isa/if_ed.c optional ed device-driver +i386/isa/if_is.c optional is device-driver +i386/isa/if_ix.c optional ix device-driver +i386/isa/if_ne.c optional ne device-driver +i386/isa/if_we.c optional we device-driver +i386/isa/isa.c optional isa device-driver +i386/isa/lpa.c optional lpa device-driver +i386/isa/lpt.c optional lpt device-driver +i386/isa/mse.c optional mse device-driver +i386/isa/npx.c optional npx device-driver +i386/isa/pccons.c optional pc device-driver +i386/isa/sio.c optional sio device-driver +i386/isa/spkr.c optional speaker +i386/isa/tw.c optional tw device-driver +i386/isa/ultra14f.c optional uha device-driver +i386/isa/wd.c optional wd device-driver +i386/isa/wt.c optional wt device-driver +scsi/cd.c optional cd +scsi/ch.c optional ch +scsi/scsiconf.c optional scbus +scsi/sd.c optional sd +scsi/st.c optional st + diff --git a/sys/i386/eisa/aha1742.c b/sys/i386/eisa/aha1742.c new file mode 100644 index 000000000000..721f6f74b86f --- /dev/null +++ b/sys/i386/eisa/aha1742.c @@ -0,0 +1,1420 @@ +/* + * Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * commenced: Sun Sep 27 18:14:01 PDT 1992 + */ + +#include <sys/types.h> +#include <ahb.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/user.h> + +#ifdef MACH /* EITHER CMU OR OSF */ +#include <i386/ipl.h> +#include <i386at/scsi.h> +#include <i386at/scsiconf.h> + +#ifdef OSF /* OSF ONLY */ +#include <sys/table.h> +#include <i386/handler.h> +#include <i386/dispatcher.h> +#include <i386/AT386/atbus.h> + +#else OSF /* CMU ONLY */ +#include <i386at/atbus.h> +#include <i386/pio.h> +#endif OSF +#endif MACH /* end of MACH specific */ + +#ifdef __386BSD__ /* 386BSD specific */ +#define isa_dev isa_device +#define dev_unit id_unit +#define dev_addr id_iobase + +#include <i386/include/pio.h> +#include <i386/isa/isa_device.h> +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> +#endif __386BSD__ + +/**/ + +#ifdef __386BSD__ +#include "ddb.h" +#if NDDB > 0 +int Debugger(); +#else NDDB +#define Debugger() panic("should call debugger here (adaptec.c)") +#endif NDDB +#endif __386BSD__ + +#ifdef MACH +int Debugger(); +#endif MACH + +typedef unsigned long int physaddr; + +#ifdef MACH +extern physaddr kvtophys(); +#define PHYSTOKV(x) phystokv(x) +#define KVTOPHYS(x) kvtophys(x) +#endif MACH + +#ifdef __386BSD__ +#define PHYSTOKV(x) (x | 0xFE000000) +#define KVTOPHYS(x) vtophys(x) +#endif __386BSD__ + +extern int delaycount; /* from clock setup code */ +#define NUM_CONCURRENT 16 /* number of concurrent ops per board */ +#define AHB_NSEG 33 /* number of dma segments supported */ +#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */ +/**/ +/***********************************************************************\ +* AHA1740 standard EISA Host ID regs (Offset from slot base) * +\***********************************************************************/ +#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */ +#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */ +#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */ +#define HID3 0xC83 /* firmware revision */ + +#define CHAR1(B1,B2) (((B1>>2) & 0x1F) | '@') +#define CHAR2(B1,B2) (((B1<<3) & 0x18) | ((B2>>5) & 0x7)|'@') +#define CHAR3(B1,B2) ((B2 & 0x1F) | '@') + +/* AHA1740 EISA board control registers (Offset from slot base) */ +#define EBCTRL 0xC84 +#define CDEN 0x01 +/***********************************************************************\ +* AHA1740 EISA board mode registers (Offset from slot base) * +\***********************************************************************/ +#define PORTADDR 0xCC0 +#define PORTADDR_ENHANCED 0x80 +#define BIOSADDR 0xCC1 +#define INTDEF 0xCC2 +#define SCSIDEF 0xCC3 +#define BUSDEF 0xCC4 +#define RESV0 0xCC5 +#define RESV1 0xCC6 +#define RESV2 0xCC7 +/**** bit definitions for INTDEF ****/ +#define INT9 0x00 +#define INT10 0x01 +#define INT11 0x02 +#define INT12 0x03 +#define INT14 0x05 +#define INT15 0x06 +#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */ +#define INTEN 0x10 +/**** bit definitions for SCSIDEF ****/ +#define HSCSIID 0x0F /* our SCSI ID */ +#define RSTPWR 0x10 /* reset scsi bus on power up or reset */ +/**** bit definitions for BUSDEF ****/ +#define B0uS 0x00 /* give up bus immediatly */ +#define B4uS 0x01 /* delay 4uSec. */ +#define B8uS 0x02 +/***********************************************************************\ +* AHA1740 ENHANCED mode mailbox control regs (Offset from slot base) * +\***********************************************************************/ +#define MBOXOUT0 0xCD0 +#define MBOXOUT1 0xCD1 +#define MBOXOUT2 0xCD2 +#define MBOXOUT3 0xCD3 + +#define ATTN 0xCD4 +#define G2CNTRL 0xCD5 +#define G2INTST 0xCD6 +#define G2STAT 0xCD7 + +#define MBOXIN0 0xCD8 +#define MBOXIN1 0xCD9 +#define MBOXIN2 0xCDA +#define MBOXIN3 0xCDB + +#define G2STAT2 0xCDC + +/*******************************************************\ +* Bit definitions for the 5 control/status registers * +\*******************************************************/ +#define ATTN_TARGET 0x0F +#define ATTN_OPCODE 0xF0 +#define OP_IMMED 0x10 +#define AHB_TARG_RESET 0x80 +#define OP_START_ECB 0x40 +#define OP_ABORT_ECB 0x50 + +#define G2CNTRL_SET_HOST_READY 0x20 +#define G2CNTRL_CLEAR_EISA_INT 0x40 +#define G2CNTRL_HARD_RESET 0x80 + +#define G2INTST_TARGET 0x0F +#define G2INTST_INT_STAT 0xF0 +#define AHB_ECB_OK 0x10 +#define AHB_ECB_RECOVERED 0x50 +#define AHB_HW_ERR 0x70 +#define AHB_IMMED_OK 0xA0 +#define AHB_ECB_ERR 0xC0 +#define AHB_ASN 0xD0 /* for target mode */ +#define AHB_IMMED_ERR 0xE0 + +#define G2STAT_BUSY 0x01 +#define G2STAT_INT_PEND 0x02 +#define G2STAT_MBOX_EMPTY 0x04 + +#define G2STAT2_HOST_READY 0x01 +/**/ + +struct ahb_dma_seg +{ + physaddr addr; + long len; +}; + +struct ahb_ecb_status +{ + u_short status; +# define ST_DON 0x0001 +# define ST_DU 0x0002 +# define ST_QF 0x0008 +# define ST_SC 0x0010 +# define ST_DO 0x0020 +# define ST_CH 0x0040 +# define ST_INT 0x0080 +# define ST_ASA 0x0100 +# define ST_SNS 0x0200 +# define ST_INI 0x0800 +# define ST_ME 0x1000 +# define ST_ECA 0x4000 + u_char ha_status; +# define HS_OK 0x00 +# define HS_CMD_ABORTED_HOST 0x04 +# define HS_CMD_ABORTED_ADAPTER 0x05 +# define HS_TIMED_OUT 0x11 +# define HS_HARDWARE_ERR 0x20 +# define HS_SCSI_RESET_ADAPTER 0x22 +# define HS_SCSI_RESET_INCOMING 0x23 + u_char targ_status; +# define TS_OK 0x00 +# define TS_CHECK_CONDITION 0x02 +# define TS_BUSY 0x08 + u_long resid_count; + u_long resid_addr; + u_short addit_status; + u_char sense_len; + u_char unused[9]; + u_char cdb[6]; +}; + +/**/ + +struct ecb +{ + u_char opcode; +# define ECB_SCSI_OP 0x01 + u_char :4; + u_char options:3; + u_char :1; + short opt1; +# define ECB_CNE 0x0001 +# define ECB_DI 0x0080 +# define ECB_SES 0x0400 +# define ECB_S_G 0x1000 +# define ECB_DSB 0x4000 +# define ECB_ARS 0x8000 + short opt2; +# define ECB_LUN 0x0007 +# define ECB_TAG 0x0008 +# define ECB_TT 0x0030 +# define ECB_ND 0x0040 +# define ECB_DAT 0x0100 +# define ECB_DIR 0x0200 +# define ECB_ST 0x0400 +# define ECB_CHK 0x0800 +# define ECB_REC 0x4000 +# define ECB_NRB 0x8000 + u_short unused1; + physaddr data; + u_long datalen; + physaddr status; + physaddr chain; + short unused2; + short unused3; + physaddr sense; + u_char senselen; + u_char cdblen; + short cksum; + u_char cdb[12]; + /*-----------------end of hardware supported fields----------------*/ + struct ecb *next; /* in free list */ + struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ + long int delta; /* difference from previous*/ + struct ecb *later,*sooner; + int flags; +#define ECB_FREE 0 +#define ECB_ACTIVE 1 +#define ECB_ABORTED 2 +#define ECB_IMMED 4 +#define ECB_IMMED_FAIL 8 + struct ahb_dma_seg ahb_dma[AHB_NSEG]; + struct ahb_ecb_status ecb_status; + struct scsi_sense_data ecb_sense; +}; + +struct ecb *ahb_soonest = (struct ecb *)0; +struct ecb *ahb_latest = (struct ecb *)0; +long int ahb_furtherest = 0; /* longest time in the timeout queue */ +/**/ + +struct ahb_data +{ + int flags; +#define AHB_INIT 0x01; + int baseport; + struct ecb ecbs[NUM_CONCURRENT]; + struct ecb *free_ecb; + int our_id; /* our scsi id */ + int vect; + struct ecb *immed_ecb; /* an outstanding immediete command */ +} ahb_data[NAHB]; + +int ahbprobe(); +int ahb_attach(); +int ahbintr(); +int ahb_scsi_cmd(); +int ahb_timeout(); +struct ecb *cheat; +void ahbminphys(); +long int ahb_adapter_info(); + +#ifdef MACH +struct isa_driver ahbdriver = { ahbprobe, 0, ahb_attach, "ahb", 0, 0, 0}; +int (*ahbintrs[])() = {ahbintr, 0}; +#endif MACH + +#ifdef __386BSD__ +struct isa_driver ahbdriver = { ahbprobe, ahb_attach, "ahb"}; +#endif __386BSD__ + +#define MAX_SLOTS 8 +static ahb_slot = 0; /* slot last board was found in */ +static ahb_unit = 0; +int ahb_debug = 0; +#define AHB_SHOWECBS 0x01 +#define AHB_SHOWINTS 0x02 +#define AHB_SHOWCMDS 0x04 +#define AHB_SHOWMISC 0x08 +#define FAIL 1 +#define SUCCESS 0 +#define PAGESIZ 4096 + +struct scsi_switch ahb_switch = +{ + ahb_scsi_cmd, + ahbminphys, + 0, + 0, + ahb_adapter_info, + 0,0,0 +}; + +/**/ +/***********************************************************************\ +* Function to send a command out through a mailbox * +\***********************************************************************/ +ahb_send_mbox( int unit + ,int opcode + ,int target + ,struct ecb *ecb) +{ + int port = ahb_data[unit].baseport; + int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ + int s = splbio(); + int stport = port + G2STAT; + + while( ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) + != (G2STAT_MBOX_EMPTY)) + && (spincount--)); + if(spincount == -1) + { + printf("ahb%d: board not responding\n",unit); + Debugger(); + } + + outl(port + MBOXOUT0,KVTOPHYS(ecb)); /* don't know this will work */ + outb(port + ATTN, opcode|target); + + splx(s); +} + +/***********************************************************************\ +* Function to poll for command completion when in poll mode * +\***********************************************************************/ +ahb_poll(int unit ,int wait) /* in msec */ +{ + int port = ahb_data[unit].baseport; + int spincount = FUDGE(delaycount) * wait; /* in msec */ + int stport = port + G2STAT; +int start = spincount; + +retry: + while( (spincount--) && (!(inb(stport) & G2STAT_INT_PEND))); + if(spincount == -1) + { + printf("ahb%d: board not responding\n",unit); + return(EIO); + } +if ((int)cheat != PHYSTOKV(inl(port + MBOXIN0))) +{ + printf("discarding %x ",inl(port + MBOXIN0)); + outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); + spinwait(50); + goto retry; +}/* don't know this will work */ + ahbintr(unit); + return(0); +} +/***********************************************************************\ +* Function to send an immediate type command to the adapter * +\***********************************************************************/ +ahb_send_immed( int unit + ,int target + ,u_long cmd) +{ + int port = ahb_data[unit].baseport; + int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ + int s = splbio(); + int stport = port + G2STAT; + + while( ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) + != (G2STAT_MBOX_EMPTY)) + && (spincount--)); + if(spincount == -1) + { + printf("ahb%d: board not responding\n",unit); + Debugger(); + } + + outl(port + MBOXOUT0,cmd); /* don't know this will work */ + outb(port + G2CNTRL, G2CNTRL_SET_HOST_READY); + outb(port + ATTN, OP_IMMED | target); + splx(s); +} + +/**/ + +/*******************************************************\ +* Check the slots looking for a board we recognise * +* If we find one, note it's address (slot) and call * +* the actual probe routine to check it out. * +\*******************************************************/ +ahbprobe(dev) +struct isa_dev *dev; +{ + int port; + u_char byte1,byte2,byte3; + ahb_slot++; + while (ahb_slot<8) + { + port = 0x1000 * ahb_slot; + byte1 = inb(port + HID0); + byte2 = inb(port + HID1); + byte3 = inb(port + HID2); + if(byte1 == 0xff) + { + ahb_slot++; + continue; + } + if ((CHAR1(byte1,byte2) == 'A') + && (CHAR2(byte1,byte2) == 'D') + && (CHAR3(byte1,byte2) == 'P') + && ((byte3 == 0 ) || (byte3 == 1))) + { + dev->dev_addr = port; + return(ahbprobe1(dev)); + } + ahb_slot++; + } + return(0); +} +/*******************************************************\ +* Check if the device can be found at the port given * +* and if so, set it up ready for further work * +* as an argument, takes the isa_dev structure from * +* autoconf.c * +\*******************************************************/ +ahbprobe1(dev) +struct isa_dev *dev; +{ + /***********************************************\ + * find unit and check we have that many defined * + \***********************************************/ + int unit = ahb_unit; +#if defined(OSF) + static ihandler_t ahb_handler[NAHB]; + static ihandler_id_t *ahb_handler_id[NAHB]; + register ihandler_t *chp = &ahb_handler[unit];; +#endif /* defined(OSF) */ + + dev->dev_unit = unit; + ahb_data[unit].baseport = dev->dev_addr; + if(unit >= NAHB) + { + printf("ahb: unit number (%d) too high\n",unit); + return(0); + } + /***********************************************\ + * Try initialise a unit at this location * + * sets up dma and bus speed, loads ahb_data[unit].vect* + \***********************************************/ + if (ahb_init(unit) != 0) + { + return(0); + } + + /***********************************************\ + * If it's there, put in it's interrupt vectors * + \***********************************************/ +#ifdef MACH +#if defined(OSF) /* OSF */ + chp->ih_level = dev->dev_pic; + chp->ih_handler = dev->dev_intr[0]; + chp->ih_resolver = i386_resolver; + chp->ih_rdev = dev; + chp->ih_stats.intr_type = INTR_DEVICE; + chp->ih_stats.intr_cnt = 0; + chp->ih_hparam[0].intparam = unit; + if ((ahb_handler_id[unit] = handler_add(chp)) != NULL) + handler_enable(ahb_handler_id[unit]); + else + panic("Unable to add ahb interrupt handler"); +#else /* CMU */ + dev->dev_pic = ahb_data[unit].vect; + take_dev_irq(dev); +#endif /* !defined(OSF) */ + printf("port=%x spl=%d\n", dev->dev_addr, dev->dev_spl); +#endif MACH +#ifdef __386BSD__ /* 386BSD */ + dev->id_irq = (1 << ahb_data[unit].vect); + dev->id_drq = -1; /* use EISA dma */ + printf("\n **"); +#endif __386BSD__ + + ahb_unit++; + return(1); +} + +/***********************************************\ +* Attach all the sub-devices we can find * +\***********************************************/ +ahb_attach(dev) +struct isa_dev *dev; +{ + int unit = dev->dev_unit; + + +#ifdef __386BSD__ + printf(" probing for scsi devices**\n"); +#endif __386BSD__ + + /***********************************************\ + * ask the adapter what subunits are present * + \***********************************************/ + scsi_attachdevs( unit, ahb_data[unit].our_id, &ahb_switch); +#if defined(OSF) + ahb_attached[unit]=1; +#endif /* defined(OSF) */ + if(!unit) /* only one for all boards */ + { + ahb_timeout(0); + } +#ifdef __386BSD__ + printf("ahb%d",unit); +#endif __386BSD__ + return; +} + +/***********************************************\ +* Return some information to the caller about * +* the adapter and it's capabilities * +\***********************************************/ +long int ahb_adapter_info(unit) +int unit; +{ + return(2); /* 2 outstanding requests at a time per device */ +} + +/***********************************************\ +* Catch an interrupt from the adaptor * +\***********************************************/ +ahbintr(unit) +{ + struct ecb *ecb; + unsigned char stat; + register i; + u_char ahbstat; + int target; + long int mboxval; + + int port = ahb_data[unit].baseport; + + if(scsi_debug & PRINTROUTINES) + printf("ahbintr "); + +#if defined(OSF) + if (!ahb_attached[unit]) + { + return(1); + } +#endif /* defined(OSF) */ + while(inb(port + G2STAT) & G2STAT_INT_PEND) + { + /***********************************************\ + * First get all the information and then * + * acknowlege the interrupt * + \***********************************************/ + ahbstat = inb(port + G2INTST); + target = ahbstat & G2INTST_TARGET; + stat = ahbstat & G2INTST_INT_STAT; + mboxval = inl(port + MBOXIN0);/* don't know this will work */ + outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); + if(scsi_debug & TRACEINTERRUPTS) + printf("status = 0x%x ",stat); + /***********************************************\ + * Process the completed operation * + \***********************************************/ + + if(stat == AHB_ECB_OK) /* common case is fast */ + { + ecb = (struct ecb *)PHYSTOKV(mboxval); + } + else + { + switch(stat) + { + case AHB_IMMED_OK: + ecb = ahb_data[unit].immed_ecb; + ahb_data[unit].immed_ecb = 0; + break; + case AHB_IMMED_ERR: + ecb = ahb_data[unit].immed_ecb; + ecb->flags |= ECB_IMMED_FAIL; + ahb_data[unit].immed_ecb = 0; + break; + case AHB_ASN: /* for target mode */ + ecb = 0; + break; + case AHB_HW_ERR: + ecb = 0; + break; + case AHB_ECB_RECOVERED: + ecb = (struct ecb *)PHYSTOKV(mboxval); + break; + case AHB_ECB_ERR: + ecb = (struct ecb *)PHYSTOKV(mboxval); + break; + default: + printf(" Unknown return from ahb%d(%x)\n",unit,ahbstat); + ecb=0; + } + } + if(ecb) + { + if(ahb_debug & AHB_SHOWCMDS ) + { + ahb_show_scsi_cmd(ecb->xs); + } + if((ahb_debug & AHB_SHOWECBS) && ecb) + printf("<int ecb(%x)>",ecb); + ahb_remove_timeout(ecb); + ahb_done(unit,ecb,((stat == AHB_ECB_OK)?SUCCESS:FAIL)); + } + } + return(1); +} + +/***********************************************\ +* We have a ecb which has been processed by the * +* adaptor, now we look to see how the operation * +* went. * +\***********************************************/ +ahb_done(unit,ecb,state) +int unit,state; +struct ecb *ecb; +{ + struct ahb_ecb_status *stat = &ecb->ecb_status; + struct scsi_sense_data *s1,*s2; + struct scsi_xfer *xs = ecb->xs; + + if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) + printf("ahb_done "); + /***********************************************\ + * Otherwise, put the results of the operation * + * into the xfer and call whoever started it * + \***********************************************/ + if(ecb->flags & ECB_IMMED) + { + if(ecb->flags & ECB_IMMED_FAIL) + { + xs->error = XS_DRIVER_STUFFUP; + } + goto done; + } + if ( (state == SUCCESS) || (xs->flags & SCSI_ERR_OK)) + { /* All went correctly OR errors expected */ + xs->resid = 0; + xs->error = 0; + } + else + { + + s1 = &(ecb->ecb_sense); + s2 = &(xs->sense); + + if(stat->ha_status) + { + switch(stat->ha_status) + { + case HS_SCSI_RESET_ADAPTER: + break; + case HS_SCSI_RESET_INCOMING: + break; + case HS_CMD_ABORTED_HOST: /* No response */ + case HS_CMD_ABORTED_ADAPTER: /* No response */ + break; + case HS_TIMED_OUT: /* No response */ + if (ahb_debug & AHB_SHOWMISC) + { + printf("timeout reported back\n"); + } + xs->error = XS_TIMEOUT; + break; + default: /* Other scsi protocol messes */ + xs->error = XS_DRIVER_STUFFUP; + if (ahb_debug & AHB_SHOWMISC) + { + printf("unexpected ha_status: %x\n", + stat->ha_status); + } + } + + } + else + { + switch(stat->targ_status) + { + case TS_CHECK_CONDITION: + /* structure copy!!!!!*/ + *s2=*s1; + xs->error = XS_SENSE; + break; + case TS_BUSY: + xs->error = XS_BUSY; + break; + default: + if (ahb_debug & AHB_SHOWMISC) + { + printf("unexpected targ_status: %x\n", + stat->targ_status); + } + xs->error = XS_DRIVER_STUFFUP; + } + } + } +done: xs->flags |= ITSDONE; + ahb_free_ecb(unit,ecb, xs->flags); + if(xs->when_done) + (*(xs->when_done))(xs->done_arg,xs->done_arg2); +} + +/***********************************************\ +* A ecb (and hence a mbx-out is put onto the * +* free list. * +\***********************************************/ +ahb_free_ecb(unit,ecb, flags) +struct ecb *ecb; +{ + unsigned int opri; + + if(scsi_debug & PRINTROUTINES) + printf("ecb%d(0x%x)> ",unit,flags); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + + ecb->next = ahb_data[unit].free_ecb; + ahb_data[unit].free_ecb = ecb; + ecb->flags = ECB_FREE; + /***********************************************\ + * If there were none, wake abybody waiting for * + * one to come free, starting with queued entries* + \***********************************************/ + if (!ecb->next) { + wakeup(&ahb_data[unit].free_ecb); + } + if (!(flags & SCSI_NOMASK)) + splx(opri); +} + +/***********************************************\ +* Get a free ecb (and hence mbox-out entry) * +\***********************************************/ +struct ecb * +ahb_get_ecb(unit,flags) +{ + unsigned opri; + struct ecb *rc; + + if(scsi_debug & PRINTROUTINES) + printf("<ecb%d(0x%x) ",unit,flags); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + /***********************************************\ + * If we can and have to, sleep waiting for one * + * to come free * + \***********************************************/ + while ((!(rc = ahb_data[unit].free_ecb)) && (!(flags & SCSI_NOSLEEP))) + { + sleep(&ahb_data[unit].free_ecb, PRIBIO); + } + if (rc) + { + ahb_data[unit].free_ecb = rc->next; + rc->flags = ECB_ACTIVE; + } + if (!(flags & SCSI_NOMASK)) + splx(opri); + return(rc); +} + + + +/***********************************************\ +* Start the board, ready for normal operation * +\***********************************************/ +ahb_init(unit) +int unit; +{ + int port = ahb_data[unit].baseport; + int intdef; + int spincount = FUDGE(delaycount) * 1000; /* 1 sec enough? */ + int i; + int stport = port + G2STAT; +#define NO_NO 1 +#ifdef NO_NO + /***********************************************\ + * reset board, If it doesn't respond, assume * + * that it's not there.. good for the probe * + \***********************************************/ + outb(port + EBCTRL,CDEN); /* enable full card */ + outb(port + PORTADDR,PORTADDR_ENHANCED); + + outb(port + G2CNTRL,G2CNTRL_HARD_RESET); + spinwait(1); + outb(port + G2CNTRL,0); + spinwait(10); + while( ((inb(stport) & G2STAT_BUSY )) + && (spincount--)); + if(spincount == -1) + { + if (ahb_debug & AHB_SHOWMISC) + printf("ahb_init: No answer from bt742a board\n"); + return(ENXIO); + } + i = inb(port + MBOXIN0) & 0xff; + if(i) + { + printf("self test failed, val = 0x%x\n",i); + return(EIO); + } +#endif + while( inb(stport) & G2STAT_INT_PEND) + { + printf("."); + outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); + spinwait(10); + } + outb(port + EBCTRL,CDEN); /* enable full card */ + outb(port + PORTADDR,PORTADDR_ENHANCED); + /***********************************************\ + * Assume we have a board at this stage * + * setup dma channel from jumpers and save int * + * level * + \***********************************************/ +#ifdef __386BSD__ + printf("ahb%d reading board settings, ",unit); +#define PRNT(x) +#else __386BSD__ + printf("ahb%d:",unit); +#define PRNT(x) printf(x) +#endif __386BSD__ + + intdef = inb(port + INTDEF); + switch(intdef & 0x07) + { + case INT9: + ahb_data[unit].vect = 9; + PRNT("int=9 "); + break; + case INT10: + ahb_data[unit].vect = 10; + PRNT("int=10 "); + break; + case INT11: + ahb_data[unit].vect = 11; + PRNT("int=11 "); + break; + case INT12: + ahb_data[unit].vect = 12; + PRNT("int=12 "); + break; + case INT14: + ahb_data[unit].vect = 14; + PRNT("int=14 "); + break; + case INT15: + ahb_data[unit].vect = 15; + PRNT("int=15 "); + break; + default: + printf("illegal int setting\n"); + return(EIO); + } + outb(port + INTDEF ,(intdef | INTEN)); /* make sure we can interrupt */ + /* who are we on the scsi bus */ + ahb_data[unit].our_id = (inb(port + SCSIDEF) & HSCSIID); + + /***********************************************\ + * link up all our ECBs into a free list * + \***********************************************/ + for (i=0; i < NUM_CONCURRENT; i++) + { + ahb_data[unit].ecbs[i].next = ahb_data[unit].free_ecb; + ahb_data[unit].free_ecb = &ahb_data[unit].ecbs[i]; + ahb_data[unit].free_ecb->flags = ECB_FREE; + } + + /***********************************************\ + * Note that we are going and return (to probe) * + \***********************************************/ + ahb_data[unit].flags |= AHB_INIT; + return( 0 ); +} + + +#ifndef min +#define min(x,y) (x < y ? x : y) +#endif min + + +void ahbminphys(bp) +struct buf *bp; +{ +#ifdef MACH +#if !defined(OSF) + bp->b_flags |= B_NPAGES; /* can support scat/gather */ +#endif /* defined(OSF) */ +#endif MACH + if(bp->b_bcount > ((AHB_NSEG-1) * PAGESIZ)) + { + bp->b_bcount = ((AHB_NSEG-1) * PAGESIZ); + } +} + +/***********************************************\ +* start a scsi operation given the command and * +* the data address. Also needs the unit, target * +* and lu * +\***********************************************/ +int ahb_scsi_cmd(xs) +struct scsi_xfer *xs; +{ + struct scsi_sense_data *s1,*s2; + struct ecb *ecb; + struct ahb_dma_seg *sg; + int seg; /* scatter gather seg being worked on */ + int i = 0; + int rc = 0; + int thiskv; + physaddr thisphys,nextphys; + int unit =xs->adapter; + int bytes_this_seg,bytes_this_page,datalen,flags; + struct iovec *iovp; + int s; + if(scsi_debug & PRINTROUTINES) + printf("ahb_scsi_cmd "); + /***********************************************\ + * get a ecb (mbox-out) to use. If the transfer * + * is from a buf (possibly from interrupt time) * + * then we can't allow it to sleep * + \***********************************************/ + flags = xs->flags; + if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ + if(flags & ITSDONE) + { + printf("Already done?"); + xs->flags &= ~ITSDONE; + } + if(!(flags & INUSE)) + { + printf("Not in use?"); + xs->flags |= INUSE; + } + if (!(ecb = ahb_get_ecb(unit,flags))) + { + xs->error = XS_DRIVER_STUFFUP; + return(TRY_AGAIN_LATER); + } + +cheat = ecb; + if(ahb_debug & AHB_SHOWECBS) + printf("<start ecb(%x)>",ecb); + if(scsi_debug & SHOWCOMMANDS) + { + ahb_show_scsi_cmd(xs); + } + ecb->xs = xs; + /***********************************************\ + * If it's a reset, we need to do an 'immediate' * + * command, and store it's ccb for later * + * if there is already an immediate waiting, * + * then WE must wait * + \***********************************************/ + if(flags & SCSI_RESET) + { + ecb->flags |= ECB_IMMED; + if(ahb_data[unit].immed_ecb) + { + return(TRY_AGAIN_LATER); + } + ahb_data[unit].immed_ecb = ecb; + if (!(flags & SCSI_NOMASK)) + { + s = splbio(); + ahb_send_immed(unit,xs->targ,AHB_TARG_RESET); + ahb_add_timeout(ecb,xs->timeout); + splx(s); + return(SUCCESSFULLY_QUEUED); + } + else + { + ahb_send_immed(unit,xs->targ,AHB_TARG_RESET); + /***********************************************\ + * If we can't use interrupts, poll on completion* + \***********************************************/ + if(scsi_debug & TRACEINTERRUPTS) + printf("wait "); + if( ahb_poll(unit,xs->timeout)) + { + ahb_free_ecb(unit,ecb,flags); + xs->error = XS_TIMEOUT; + return(HAD_ERROR); + } + return(COMPLETE); + } + } + /***********************************************\ + * Put all the arguments for the xfer in the ecb * + \***********************************************/ + ecb->opcode = ECB_SCSI_OP; + ecb->opt1 = ECB_SES|ECB_DSB|ECB_ARS; + if(xs->datalen) + { + ecb->opt1 |= ECB_S_G; + } + ecb->opt2 = xs->lu | ECB_NRB; + ecb->cdblen = xs->cmdlen; + ecb->sense = KVTOPHYS(&(ecb->ecb_sense)); + ecb->senselen = sizeof(ecb->ecb_sense); + ecb->status = KVTOPHYS(&(ecb->ecb_status)); + + if(xs->datalen) + { /* should use S/G only if not zero length */ + ecb->data = KVTOPHYS(ecb->ahb_dma); + sg = ecb->ahb_dma ; + seg = 0; + if(flags & SCSI_DATA_UIO) + { + iovp = ((struct uio *)xs->data)->uio_iov; + datalen = ((struct uio *)xs->data)->uio_iovcnt; + xs->datalen = 0; + while ((datalen) && (seg < AHB_NSEG)) + { + sg->addr = (physaddr)iovp->iov_base; + xs->datalen += sg->len = iovp->iov_len; + if(scsi_debug & SHOWSCATGATH) + printf("(0x%x@0x%x)" + ,iovp->iov_len + ,iovp->iov_base); + sg++; + iovp++; + seg++; + datalen--; + } + } + else + { + /***********************************************\ + * Set up the scatter gather block * + \***********************************************/ + + if(scsi_debug & SHOWSCATGATH) + printf("%d @0x%x:- ",xs->datalen,xs->data); + datalen = xs->datalen; + thiskv = (int)xs->data; + thisphys = KVTOPHYS(thiskv); + + while ((datalen) && (seg < AHB_NSEG)) + { + bytes_this_seg = 0; + + /* put in the base address */ + sg->addr = thisphys; + + if(scsi_debug & SHOWSCATGATH) + printf("0x%x",thisphys); + + /* do it at least once */ + nextphys = thisphys; + while ((datalen) && (thisphys == nextphys)) + /*********************************************\ + * This page is contiguous (physically) with * + * the the last, just extend the length * + \*********************************************/ + { + /* how far to the end of the page */ + nextphys= (thisphys & (~(PAGESIZ - 1))) + + PAGESIZ; + bytes_this_page = nextphys - thisphys; + /**** or the data ****/ + bytes_this_page = min(bytes_this_page + ,datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; + + /* get more ready for the next page */ + thiskv = (thiskv & (~(PAGESIZ - 1))) + + PAGESIZ; + if(datalen) + thisphys = KVTOPHYS(thiskv); + } + /********************************************\ + * next page isn't contiguous, finish the seg * + \********************************************/ + if(scsi_debug & SHOWSCATGATH) + printf("(0x%x)",bytes_this_seg); + sg->len = bytes_this_seg; + sg++; + seg++; + } + } /*end of iov/kv decision */ + ecb->datalen = seg * sizeof(struct ahb_dma_seg); + if(scsi_debug & SHOWSCATGATH) + printf("\n"); + if (datalen) + { /* there's still data, must have run out of segs! */ + printf("ahb_scsi_cmd%d: more than %d DMA segs\n", + unit,AHB_NSEG); + xs->error = XS_DRIVER_STUFFUP; + ahb_free_ecb(unit,ecb,flags); + return(HAD_ERROR); + } + + } + else + { /* No data xfer, use non S/G values */ + ecb->data = (physaddr)0; + ecb->datalen = 0; + } + ecb->chain = (physaddr)0; + /***********************************************\ + * Put the scsi command in the ecb and start it * + \***********************************************/ + bcopy(xs->cmd, ecb->cdb, xs->cmdlen); + /***********************************************\ + * Usually return SUCCESSFULLY QUEUED * + \***********************************************/ + if (!(flags & SCSI_NOMASK)) + { + s = splbio(); + ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb); + ahb_add_timeout(ecb,xs->timeout); + splx(s); + if(scsi_debug & TRACEINTERRUPTS) + printf("cmd_sent "); + return(SUCCESSFULLY_QUEUED); + } + /***********************************************\ + * If we can't use interrupts, poll on completion* + \***********************************************/ + ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb); + if(scsi_debug & TRACEINTERRUPTS) + printf("cmd_wait "); + do + { + if(ahb_poll(unit,xs->timeout)) + { + if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n"); + ahb_send_mbox(unit,OP_ABORT_ECB,xs->targ,ecb); + if(ahb_poll(unit,2000)) + { + printf("abort failed in wait\n"); + ahb_free_ecb(unit,ecb,flags); + } + xs->error = XS_DRIVER_STUFFUP; + splx(s); + return(HAD_ERROR); + } + } while (!(xs->flags & ITSDONE));/* something (?) else finished */ + splx(s); +scsi_debug = 0;ahb_debug = 0; + if(xs->error) + { + return(HAD_ERROR); + } + return(COMPLETE); +} + +/* + * +----------+ +----------+ +----------+ + * ahb_soonest--->| later |--->| later|--->| later|--->0 + * | [Delta] | | [Delta] | | [Delta] | + * 0<---|sooner |<---|sooner |<---|sooner |<---ahb_latest + * +----------+ +----------+ +----------+ + * + * ahb_furtherest = sum(Delta[1..n]) + */ +ahb_add_timeout(ecb,time) +struct ecb *ecb; +int time; +{ + int timeprev; + struct ecb *prev; + int s = splbio(); + + if(prev = ahb_latest) /* yes, an assign */ + { + timeprev = ahb_furtherest; + } + else + { + timeprev = 0; + } + while(prev && (timeprev > time)) + { + timeprev -= prev->delta; + prev = prev->sooner; + } + if(prev) + { + ecb->delta = time - timeprev; + if( ecb->later = prev->later) /* yes an assign */ + { + ecb->later->sooner = ecb; + ecb->later->delta -= ecb->delta; + } + else + { + ahb_furtherest = time; + ahb_latest = ecb; + } + ecb->sooner = prev; + prev->later = ecb; + } + else + { + if( ecb->later = ahb_soonest) /* yes, an assign*/ + { + ecb->later->sooner = ecb; + ecb->later->delta -= time; + } + else + { + ahb_furtherest = time; + ahb_latest = ecb; + } + ecb->delta = time; + ecb->sooner = (struct ecb *)0; + ahb_soonest = ecb; + } + splx(s); +} + +ahb_remove_timeout(ecb) +struct ecb *ecb; +{ + int s = splbio(); + + if(ecb->sooner) + { + ecb->sooner->later = ecb->later; + } + else + { + ahb_soonest = ecb->later; + } + if(ecb->later) + { + ecb->later->sooner = ecb->sooner; + ecb->later->delta += ecb->delta; + } + else + { + ahb_latest = ecb->sooner; + ahb_furtherest -= ecb->delta; + } + ecb->sooner = ecb->later = (struct ecb *)0; + splx(s); +} + + +extern int hz; +#define ONETICK 500 /* milliseconds */ +#define SLEEPTIME ((hz * 1000) / ONETICK) +ahb_timeout(arg) +int arg; +{ + struct ecb *ecb; + int unit; + int s = splbio(); + + while( ecb = ahb_soonest ) + { + if(ecb->delta <= ONETICK) + /***********************************************\ + * It has timed out, we need to do some work * + \***********************************************/ + { + unit = ecb->xs->adapter; + printf("ahb%d:%d device timed out\n",unit + ,ecb->xs->targ); + if(ahb_debug & AHB_SHOWECBS) + ahb_print_active_ecb(); + + /***************************************\ + * Unlink it from the queue * + \***************************************/ + ahb_remove_timeout(ecb); + + /***************************************\ + * If it's immediate, don't try abort it * + \***************************************/ + if(ecb->flags & ECB_IMMED) + { + ecb->xs->retries = 0; /* I MEAN IT ! */ + ecb->flags |= ECB_IMMED_FAIL; + ahb_done(unit,ecb,FAIL); + continue; + } + /***************************************\ + * If it has been through before, then * + * a previous abort has failed, don't * + * try abort again * + \***************************************/ + if(ecb->flags == ECB_ABORTED) /* abort timed out */ + { + printf("AGAIN"); + ecb->xs->retries = 0; /* I MEAN IT ! */ + ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST; + ahb_done(unit,ecb,FAIL); + } + else /* abort the operation that has timed out */ + { + printf("\n"); + ahb_send_mbox(unit,OP_ABORT_ECB,ecb->xs->targ,ecb); + /* 2 secs for the abort */ + ahb_add_timeout(ecb,2000 + ONETICK); + ecb->flags = ECB_ABORTED; + } + } + else + /***********************************************\ + * It has not timed out, adjust and leave * + \***********************************************/ + { + ecb->delta -= ONETICK; + ahb_furtherest -= ONETICK; + break; + } + } + splx(s); + timeout(ahb_timeout,arg,SLEEPTIME); +} + +ahb_show_scsi_cmd(struct scsi_xfer *xs) +{ + u_char *b = (u_char *)xs->cmd; + int i = 0; + if(!(xs->flags & SCSI_RESET)) + { + printf("ahb%d:%d:%d-" + ,xs->adapter + ,xs->targ + ,xs->lu); + while(i < xs->cmdlen ) + { + if(i) printf(","); + printf("%x",b[i++]); + } + printf("-\n"); + } + else + { + printf("ahb%d:%d:%d-RESET-\n" + ,xs->adapter + ,xs->targ + ,xs->lu + ); + } +} +ahb_print_ecb(ecb) +struct ecb *ecb; +{ + printf("ecb:%x op:%x cmdlen:%d senlen:%d\n" + ,ecb + ,ecb->opcode + ,ecb->cdblen + ,ecb->senselen); + printf(" datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n" + ,ecb->datalen + ,ecb->ecb_status.ha_status + ,ecb->ecb_status.targ_status + ,ecb->delta + ,ecb->flags); + ahb_show_scsi_cmd(ecb->xs); +} + +ahb_print_active_ecb() +{ + struct ecb *ecb; + ecb = ahb_soonest; + + while(ecb) + { + ahb_print_ecb(ecb); + ecb = ecb->later; + } + printf("Furtherest = %d\n",ahb_furtherest); +} diff --git a/sys/i386/i386/autoconf.c b/sys/i386/i386/autoconf.c new file mode 100644 index 000000000000..7eee991a9466 --- /dev/null +++ b/sys/i386/i386/autoconf.c @@ -0,0 +1,213 @@ +/*- + * 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. + * + * @(#)autoconf.c 7.1 (Berkeley) 5/9/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00117 + * -------------------- ----- ---------------------- + * + * 09 Apr 93 ???(From sun-lamp) Fix to report sd when Julians + * scsi code is used, allow you to swap + * root floppies during a boot + */ +static char rcsid[] = "$Header: /b/source/CVS/src/sys.386bsd/i386/i386/autoconf.c,v 1.3 1993/04/10 21:58:52 cgd Exp $"; + +/* + * Setup the system to run on the current machine. + * + * Configure() is called at boot time and initializes the vba + * device tables and the memory controller monitoring. Available + * devices are determined (from possibilities mentioned in ioconf.c), + * and the drivers are initialized. + */ +#include "param.h" +#include "systm.h" +#include "buf.h" +#include "dkstat.h" +#include "conf.h" +#include "dmap.h" +#include "reboot.h" + +#include "machine/pte.h" + +/* + * The following several variables are related to + * the configuration process, and are used in initializing + * the machine. + */ +int dkn; /* number of iostat dk numbers assigned so far */ +extern int cold; /* cold start flag initialized in locore.s */ + +/* + * Determine i/o configuration for a machine. + */ +configure() +{ + +#include "isa.h" +#if NISA > 0 + isa_configure(); +#endif + +#if GENERICxxx + if ((boothowto & RB_ASKNAME) == 0) + setroot(); + setconf(); +#else + setroot(); +#endif + /* + * Configure swap area and related system + * parameter based on device(s) used. + */ + swapconf(); + cold = 0; +} + +/* + * Configure swap space and related parameters. + */ +swapconf() +{ + register struct swdevt *swp; + register int nblks; +extern int Maxmem; + + for (swp = swdevt; swp->sw_dev > 0; swp++) + { + unsigned d = major(swp->sw_dev); + + if (d > nblkdev) break; + if (bdevsw[d].d_psize) { + nblks = (*bdevsw[d].d_psize)(swp->sw_dev); + if (nblks > 0 && + (swp->sw_nblks == 0 || swp->sw_nblks > nblks)) + swp->sw_nblks = nblks; + else + swp->sw_nblks = 0; + } + swp->sw_nblks = ctod(dtoc(swp->sw_nblks)); + } + if (dumplo == 0 && bdevsw[major(dumpdev)].d_psize) + /*dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) - physmem;*/ + dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) - + Maxmem*NBPG/512; + if (dumplo < 0) + dumplo = 0; +} + +#define DOSWAP /* change swdevt and dumpdev */ +u_long bootdev = 0; /* should be dev_t, but not until 32 bits */ + +#include "sd.h" +static char devname[][2] = { + 'w','d', /* 0 = wd */ + 's','w', /* 1 = sw */ + 'f','d', /* 2 = fd */ + 'w','t', /* 3 = wt */ +#if NSD < 1 + 'a','s', /* 4 = as */ +#else + 's','d', /* 4 = sd -- new SCSI system */ +#endif +}; + +#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, adaptor; + dev_t temp, orootdev; + struct swdevt *swp; + +/*printf("howto %x bootdev %x ", boothowto, bootdev);*/ + if (boothowto & RB_DFLTROOT || + (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC) + return; + majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK; + if (majdev > sizeof(devname) / sizeof(devname[0])) + return; + adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK; + part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK; + unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK; + 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; + if (devname[majdev][0] == 'f' && devname[majdev][1] == 'd') { + printf(""); + printf("* insert the floppy you want to have mounted as\n"); + printf("* root, and hit any key to continue booting:\n"); + cngetc(); + printf(""); + } + printf("changing root device to %c%c%d%c\n", + devname[majdev][0], devname[majdev][1], + mindev >> PARTITIONSHIFT, part + 'a'); +#ifdef DOSWAP + mindev &= ~PARTITIONMASK; + for (swp = swdevt; swp->sw_dev; swp++) { + if (majdev == major(swp->sw_dev) && + mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) { + + temp = swdevt[0].sw_dev; + swdevt[0].sw_dev = swp->sw_dev; + swp->sw_dev = temp; + break; + } + } + if (swp->sw_dev == 0) + 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 +} diff --git a/sys/i386/i386/conf.c b/sys/i386/i386/conf.c new file mode 100644 index 000000000000..0189092fc050 --- /dev/null +++ b/sys/i386/i386/conf.c @@ -0,0 +1,480 @@ +/*- + * 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. + * + * @(#)conf.c 5.8 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 5 00160 + * -------------------- ----- ---------------------- + * + * 10 Feb 93 Jordan K. Hubbard Added select entry for com driver + * 10 Feb 93 Julian Elischer Add empty table entries + * so we can allocate numbers + * 15 Feb 93 Julian Elischer Add basic SCSI device entries + * 16 Feb 93 Julian Elischer add entries for scsi media changer + * 01 Mar 93 Jordan K. Hubbard Reserve major numbers for codrv, fd, bpf + * 10 Mar 83 Rodney W. Grimes General clean up of the above patches + * 06 Apr 93 Rodney W. Grimes Fixed NLPT for LPA driver case, added + * spkr, dcfclock + * 23 Apr 93 Holger Veit added codrv + * 25 May 93 Bruce Evans New fast interrupt serial driver (sio) + * Gene Stark Xten power controller info added (tw) + * Rick Macklem Bus mouse driver (mse) + * + */ +static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/i386/RCS/conf.c,v 1.2 92/01/21 14:21:57 william Exp Locker: toor $"; + +#include "param.h" +#include "systm.h" +#include "buf.h" +#include "ioctl.h" +#include "tty.h" +#include "conf.h" + +int nullop(), enxio(), enodev(), rawread(), rawwrite(), swstrategy(); +int rawread(), rawwrite(), swstrategy(); + +#include "wd.h" +#if NWD > 0 +int wdopen(),wdclose(),wdstrategy(),wdioctl(); +int wddump(),wdsize(); +#else +#define wdopen enxio +#define wdclose enxio +#define wdstrategy enxio +#define wdioctl enxio +#define wddump enxio +#define wdsize NULL +#endif + +#include "as.h" +#if NAS > 0 +int asopen(),asclose(),asstrategy(),asioctl(); +int /*asdump(),*/assize(); +#define asdump enxio +#else +#define asopen enxio +#define asclose enxio +#define asstrategy enxio +#define asioctl enxio +#define asdump enxio +#define assize NULL +#endif + +#include "sd.h" +#if NSD > 0 +int sdopen(),sdclose(),sdstrategy(),sdioctl(); +int /*sddump(),*/sdsize(); +#define sddump enxio +#else +#define sdopen enxio +#define sdclose enxio +#define sdstrategy enxio +#define sdioctl enxio +#define sddump enxio +#define sdsize NULL +#endif + +#include "st.h" +#if NST > 0 +int stopen(),stclose(),ststrategy(),stioctl(); +/*int stdump(),stsize();*/ +#define stdump enxio +#define stsize NULL +#else +#define stopen enxio +#define stclose enxio +#define ststrategy enxio +#define stioctl enxio +#define stdump enxio +#define stsize NULL +#endif + +#include "cd.h" +#if NCD > 0 +int cdopen(),cdclose(),cdstrategy(),cdioctl(); +int /*cddump(),*/cdsize(); +#define cddump enxio +#else +#define cdopen enxio +#define cdclose enxio +#define cdstrategy enxio +#define cdioctl enxio +#define cddump enxio +#define cdsize NULL +#endif + +#include "ch.h" +#if NCH > 0 +int chopen(),chclose(),chioctl(); +#else +#define chopen enxio +#define chclose enxio +#define chioctl enxio +#endif + +#include "wt.h" +#if NWT > 0 +int wtopen(),wtclose(),wtstrategy(),wtioctl(); +int wtdump(),wtsize(); +#else +#define wtopen enxio +#define wtclose enxio +#define wtstrategy enxio +#define wtioctl enxio +#define wtdump enxio +#define wtsize NULL +#endif + +#include "fd.h" +#if NFD > 0 +int Fdopen(),fdclose(),fdstrategy(); +#define fdioctl enxio +#define fddump enxio +#define fdsize NULL +#else +#define Fdopen enxio +#define fdclose enxio +#define fdstrategy enxio +#define fdioctl enxio +#define fddump enxio +#define fdsize NULL +#endif + +int swstrategy(),swread(),swwrite(); + +struct bdevsw bdevsw[] = +{ + { wdopen, wdclose, wdstrategy, wdioctl, /*0*/ + wddump, wdsize, NULL }, + { enodev, enodev, swstrategy, enodev, /*1*/ + enodev, enodev, NULL }, + { Fdopen, fdclose, fdstrategy, fdioctl, /*2*/ + fddump, fdsize, NULL }, + { wtopen, wtclose, wtstrategy, wtioctl, /*3*/ + wtdump, wtsize, B_TAPE }, +#if NSD > 0 + { sdopen, sdclose, sdstrategy, sdioctl, /*4*/ + sddump, sdsize, NULL }, +#else NSD > 0 + { asopen, asclose, asstrategy, asioctl, /*4*/ + asdump, assize, NULL }, +#endif NSD > 0 + { stopen, stclose, ststrategy, stioctl, /*5*/ + stdump, stsize, NULL }, + { cdopen, cdclose, cdstrategy, cdioctl, /*6*/ + cddump, cdsize, NULL }, +/* + * If you need a bdev major number, please contact the 386bsd patchkit + * coordinator by sending mail to "patches@cs.montana.edu". + * If you assign one yourself it may conflict with someone else. + */ +}; +int nblkdev = sizeof (bdevsw) / sizeof (bdevsw[0]); + +int cnopen(),cnclose(),cnread(),cnwrite(),cnioctl(),cnselect(); + +int pcopen(),pcclose(),pcread(),pcwrite(),pcioctl(),pcmmap(); +extern struct tty pccons; + +int cttyopen(), cttyread(), cttywrite(), cttyioctl(), cttyselect(); + +int mmrw(); +#define mmselect seltrue + +#include "pty.h" +#if NPTY > 0 +int ptsopen(),ptsclose(),ptsread(),ptswrite(),ptsstop(); +int ptcopen(),ptcclose(),ptcread(),ptcwrite(),ptcselect(); +int ptyioctl(); +struct tty pt_tty[]; +#else +#define ptsopen enxio +#define ptsclose enxio +#define ptsread enxio +#define ptswrite enxio +#define ptcopen enxio +#define ptcclose enxio +#define ptcread enxio +#define ptcwrite enxio +#define ptyioctl enxio +#define pt_tty NULL +#define ptcselect enxio +#define ptsstop nullop +#endif + +#include "com.h" +#if NCOM > 0 +int comopen(),comclose(),comread(),comwrite(),comioctl(),comselect(); +#define comreset enxio +extern struct tty com_tty[]; +#else +#define comopen enxio +#define comclose enxio +#define comread enxio +#define comwrite enxio +#define comioctl enxio +#define comreset enxio +#define comselect enxio +#define com_tty NULL +#endif + +int logopen(),logclose(),logread(),logioctl(),logselect(); + +int ttselect(), seltrue(); + +#include "lpt.h" +#if NLPT > 0 +int lptopen(),lptclose(),lptwrite(),lptioctl(); +#else +#define lptopen enxio +#define lptclose enxio +#define lptwrite enxio +#define lptioctl enxio +#endif + +#include "co.h" +#if NCO > 0 +int coopen(),coclose(),coread(),coioctl(),coselect(),comap(); +#define pcmmap comap +#else +#define coopen enxio +#define coclose enxio +#define coread enxio +#define coioctl enxio +#define coselect enxio +#define comap enxio +#endif + +#include "tw.h" +#if NTW > 0 +int twopen(),twclose(),twread(),twwrite(),twselect(); +#else +#define twopen enxio +#define twclose enxio +#define twread enxio +#define twwrite enxio +#define twselect enxio +#endif + +int fdopen(); + +#include "bpfilter.h" +#if NBPFILTER > 0 +int bpfopen(),bpfclose(),bpfread(),bpfwrite(),bpfselect(),bpfioctl(); +#else +#define bpfopen enxio +#define bpfclose enxio +#define bpfread enxio +#define bpfwrite enxio +#define bpfselect enxio +#define bpfioctl enxio +#endif + +#include "dcfclk.h" +#if NDCFCLK > 0 +int dcfclkopen(),dcfclkclose(),dcfclkread(),dcfclkioctl(),dcfclkselect(); +#else +#define dcfclkopen enxio +#define dcfclkclose enxio +#define dcfclkread enxio +#define dcfclkioctl enxio +#define dcfclkselect enxio +#endif + +#include "lpa.h" +#if NLPA > 0 +int lpaopen(),lpaclose(),lpawrite(),lpaioctl(); +#else +#define lpaopen enxio +#define lpaclose enxio +#define lpawrite enxio +#define lpaioctl enxio +#endif + +#include "speaker.h" +#if NSPEAKER > 0 +int spkropen(),spkrclose(),spkrwrite(),spkrioctl(); +#else +#define spkropen enxio +#define spkrclose enxio +#define spkrwrite enxio +#define spkrioctl enxio +#endif + +#include "mse.h" +#if NMSE > 0 +int mseopen(),mseclose(),mseread(),mseselect(); +#else +#define mseopen enxio +#define mseclose enxio +#define mseread enxio +#define mseselect enxio +#endif + +#include "sio.h" +#if NSIO > 0 +int sioopen(),sioclose(),sioread(),siowrite(),sioioctl(),sioselect(), + siostop(); +#define sioreset enxio +extern struct tty sio_tty[]; +#else +#define sioopen enxio +#define sioclose enxio +#define sioread enxio +#define siowrite enxio +#define sioioctl enxio +#define siostop enxio +#define sioreset enxio +#define sioselect enxio +#define sio_tty NULL +#endif + +struct cdevsw cdevsw[] = +{ + { cnopen, cnclose, cnread, cnwrite, /*0*/ + cnioctl, nullop, nullop, NULL, /* console */ + cnselect, enodev, NULL }, + { cttyopen, nullop, cttyread, cttywrite, /*1*/ + cttyioctl, nullop, nullop, NULL, /* tty */ + cttyselect, enodev, NULL }, + { nullop, nullop, mmrw, mmrw, /*2*/ + enodev, nullop, nullop, NULL, /* memory */ + mmselect, enodev, NULL }, + { wdopen, wdclose, rawread, rawwrite, /*3*/ + wdioctl, enodev, nullop, NULL, /* wd */ + seltrue, enodev, wdstrategy }, + { nullop, nullop, rawread, rawwrite, /*4*/ + enodev, enodev, nullop, NULL, /* swap */ + enodev, enodev, swstrategy }, + { ptsopen, ptsclose, ptsread, ptswrite, /*5*/ + ptyioctl, ptsstop, nullop, pt_tty, /* ttyp */ + ttselect, enodev, NULL }, + { ptcopen, ptcclose, ptcread, ptcwrite, /*6*/ + ptyioctl, nullop, nullop, pt_tty, /* ptyp */ + ptcselect, enodev, NULL }, + { logopen, logclose, logread, enodev, /*7*/ + logioctl, enodev, nullop, NULL, /* klog */ + logselect, enodev, NULL }, + { comopen, comclose, comread, comwrite, /*8*/ + comioctl, enodev, comreset, com_tty, /* com */ + comselect, enodev, NULL }, + { Fdopen, fdclose, rawread, rawwrite, /*9*/ + fdioctl, enodev, nullop, NULL, /* Fd (!=fd) */ + seltrue, enodev, fdstrategy }, + { wtopen, wtclose, rawread, rawwrite, /*10*/ + wtioctl, enodev, nullop, NULL, /* wt */ + seltrue, enodev, wtstrategy }, + { enodev, enodev, enodev, enodev, /*11*/ + enodev, enodev, nullop, NULL, + seltrue, enodev, enodev }, + { pcopen, pcclose, pcread, pcwrite, /*12*/ + pcioctl, nullop, nullop, &pccons, /* pc */ + ttselect, pcmmap, NULL }, +#if NSD > 0 + { sdopen, sdclose, rawread, rawwrite, /*13*/ + sdioctl, enodev, nullop, NULL, /* sd */ + seltrue, enodev, sdstrategy }, +#else NSD > 0 + { asopen, asclose, rawread, rawwrite, /*13*/ + asioctl, enodev, nullop, NULL, /* as */ + seltrue, enodev, asstrategy }, +#endif NSD > 0 + { stopen, stclose, rawread, rawwrite, /*14*/ + stioctl, enodev, nullop, NULL, /* st */ + seltrue, enodev, ststrategy }, + { cdopen, cdclose, rawread, enodev, /*15*/ + cdioctl, enodev, nullop, NULL, /* cd */ + seltrue, enodev, cdstrategy }, + { lptopen, lptclose, nullop, lptwrite, /*16*/ + lptioctl, nullop, nullop, NULL, /* lpt */ + seltrue, enodev, enodev}, + { chopen, chclose, enxio, enxio, /*17*/ + chioctl, enxio, enxio, NULL, /* ch */ + enxio, enxio, enxio }, + { enxio, enxio, enxio, enxio, /*18*/ + enxio, enxio, enxio, NULL, /* scsi generic */ + enxio, enxio, enxio }, + { twopen, twclose, twread, twwrite, /*19*/ + enodev, nullop, nullop, NULL, /* tw */ + twselect, enodev, enodev }, + { enxio, enxio, enxio, enxio, /*20*/ + enxio, enxio, enxio, NULL, /* soundblaster?*/ + enxio, enxio, enxio }, + { coopen, coclose, coread, enxio, /*21*/ + coioctl, nullop, nullop, NULL, /* co */ + coselect, comap, NULL }, + { fdopen, enxio, enxio, enxio, /*22*/ + enxio, enxio, enxio, NULL, /* fd (!=Fd) */ + enxio, enxio, enxio }, + { bpfopen, bpfclose, bpfread, bpfwrite, /*23*/ + bpfioctl, enodev, nullop, NULL, /* bpf */ + bpfselect, enodev, NULL }, + { dcfclkopen, dcfclkclose, dcfclkread, enodev, /*24*/ + dcfclkioctl, enodev, nullop, NULL, /* dcfclk */ + dcfclkselect, enodev, NULL }, + { lpaopen, lpaclose, nullop, lpawrite, /*25*/ + lpaioctl, nullop, nullop, NULL, /* lpa */ + seltrue, enodev, enodev}, + { spkropen, spkrclose, enxio, spkrwrite, /*26*/ + spkrioctl, enxio, enxio, NULL, /* spkr */ + enxio, enxio, enxio }, + { mseopen, mseclose, mseread, nullop, /*27*/ + nullop, enodev, nullop, NULL, /* mse */ + mseselect, enodev, NULL }, + { sioopen, sioclose, sioread, siowrite, /*28*/ + sioioctl, siostop, sioreset, sio_tty, /* sio */ + sioselect, enodev, NULL }, +/* + * If you need a cdev major number, please contact the 386bsd patchkit + * coordinator by sending mail to "patches@cs.montana.edu". + * If you assign one yourself it may then conflict with someone else. + */ +}; +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); diff --git a/sys/i386/i386/cons.c b/sys/i386/i386/cons.c new file mode 100644 index 000000000000..6189d721115f --- /dev/null +++ b/sys/i386/i386/cons.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1991 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. + * + * 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. + * + * @(#)cons.c 7.2 (Berkeley) 5/9/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00083 + * -------------------- ----- ---------------------- + * + * 16 Aug 92 Pace Willisson /dev/console redirect (xterm -C, etc.) + * 14 Mar 93 Chris G. Demetriou Moved pg() here from isa/pccons.c + */ + + +#include "sys/param.h" +#include "sys/proc.h" +#include "sys/user.h" +#include "sys/systm.h" +#include "sys/buf.h" +#include "sys/ioctl.h" +#include "sys/tty.h" +#include "sys/file.h" +#include "sys/conf.h" + +#include "cons.h" + +/* XXX - all this could be autoconfig()ed */ +int pccnprobe(), pccninit(), pccngetc(), pccnputc(); +#include "com.h" +#if NCOM > 0 +int comcnprobe(), comcninit(), comcngetc(), comcnputc(); +#endif + +struct consdev constab[] = { + { pccnprobe, pccninit, pccngetc, pccnputc }, +#if NCOM > 0 + { comcnprobe, comcninit, comcngetc, comcnputc }, +#endif + { 0 }, +}; +/* end XXX */ + +struct tty *constty = 0; /* virtual console output device */ +struct consdev *cn_tab; /* physical console device info */ +struct tty *cn_tty; /* XXX: console tty struct for tprintf */ + +cninit() +{ + register struct consdev *cp; + + /* + * Collect information about all possible consoles + * and find the one with highest priority + */ + for (cp = constab; cp->cn_probe; cp++) { + (*cp->cn_probe)(cp); + if (cp->cn_pri > CN_DEAD && + (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri)) + cn_tab = cp; + } + /* + * No console, we can handle it + */ + if ((cp = cn_tab) == NULL) + return; + /* + * Turn on console + */ + cn_tty = cp->cn_tp; + (*cp->cn_init)(cp); +} + +cnopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + if (cn_tab == NULL) + return (0); + dev = cn_tab->cn_dev; + return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p)); +} + +cnclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + if (cn_tab == NULL) + return (0); + dev = cn_tab->cn_dev; + return ((*cdevsw[major(dev)].d_close)(dev, flag, mode, p)); +} + +cnread(dev, uio, flag) + dev_t dev; + struct uio *uio; +{ + if (cn_tab == NULL) + return (0); + dev = cn_tab->cn_dev; + return ((*cdevsw[major(dev)].d_read)(dev, uio, flag)); +} + +cnwrite(dev, uio, flag) + dev_t dev; + struct uio *uio; +{ + if (cn_tab == NULL) + return (0); + if (constty) /* 16 Aug 92*/ + dev = constty->t_dev; + else + dev = cn_tab->cn_dev; + return ((*cdevsw[major(dev)].d_write)(dev, uio, flag)); +} + +cnioctl(dev, cmd, data, flag, p) + dev_t dev; + caddr_t data; + struct proc *p; +{ + int error; + + if (cn_tab == NULL) + return (0); + /* + * Superuser can always use this to wrest control of console + * output from the "virtual" console. + */ + if (cmd == TIOCCONS && constty) { + error = suser(p->p_ucred, (u_short *) NULL); + if (error) + return (error); + constty = NULL; + return (0); + } + dev = cn_tab->cn_dev; + return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p)); +} + +/*ARGSUSED*/ +cnselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; +{ + if (cn_tab == NULL) + return (1); + return (ttselect(cn_tab->cn_dev, rw, p)); +} + +cngetc() +{ + if (cn_tab == NULL) + return (0); + return ((*cn_tab->cn_getc)(cn_tab->cn_dev)); +} + +cnputc(c) + register int c; +{ + if (cn_tab == NULL) + return; + if (c) { + (*cn_tab->cn_putc)(cn_tab->cn_dev, c); + if (c == '\n') + (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); + } +} + +pg(p,q,r,s,t,u,v,w,x,y,z) char *p; { + printf(p,q,r,s,t,u,v,w,x,y,z); + printf("\n>"); + return(cngetc()); +} + + diff --git a/sys/i386/i386/cons.h b/sys/i386/i386/cons.h new file mode 100644 index 000000000000..b3c706433ade --- /dev/null +++ b/sys/i386/i386/cons.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1991 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. + * + * 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. + * + * @(#)cons.h 7.2 (Berkeley) 5/9/91 + */ + + +struct consdev { + int (*cn_probe)(); /* probe hardware and fill in consdev info */ + int (*cn_init)(); /* turn on as console */ + int (*cn_getc)(); /* kernel getchar interface */ + int (*cn_putc)(); /* kernel putchar interface */ + struct tty *cn_tp; /* tty structure for console device */ + dev_t cn_dev; /* major/minor of device */ + short cn_pri; /* pecking order; the higher the better */ +}; + +/* values for cn_pri - reflect our policy for console selection */ +#define CN_DEAD 0 /* device doesn't exist */ +#define CN_NORMAL 1 /* device exists but is nothing special */ +#define CN_INTERNAL 2 /* "internal" bit-mapped display */ +#define CN_REMOTE 3 /* serial interface with remote bit set */ + +/* XXX */ +#define CONSMAJOR 0 + +#ifdef KERNEL +extern struct consdev constab[]; +extern struct consdev *cn_tab; +extern struct tty *cn_tty; +#endif diff --git a/sys/i386/i386/db_disasm.c b/sys/i386/i386/db_disasm.c new file mode 100644 index 000000000000..20430b674133 --- /dev/null +++ b/sys/i386/i386/db_disasm.c @@ -0,0 +1,1397 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_disasm.c,v $ + * Revision 1.1 1992/03/25 21:42:01 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:11:03 mrt + * Changed to new Mach copyright + * [91/02/01 17:31:03 mrt] + * + * Revision 2.2 90/08/27 21:55:56 dbg + * Fix register operand for move to/from control/test/debug + * register instructions. Add i486 instructions. + * [90/08/27 dbg] + * + * Import db_sym.h. Print instruction displacements in + * current radix (signed). Change calling sequence of + * db_disasm. + * [90/08/21 dbg] + * Fix includes. + * [90/08/08 dbg] + * Created. + * [90/07/25 dbg] + * + */ + +/* + * Instruction disassembler. + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> + +#include <ddb/db_access.h> +#include <ddb/db_sym.h> + +/* + * Size attributes + */ +#define BYTE 0 +#define WORD 1 +#define LONG 2 +#define QUAD 3 +#define SNGL 4 +#define DBLR 5 +#define EXTR 6 +#define SDEP 7 +#define NONE 8 + +/* + * Addressing modes + */ +#define E 1 /* general effective address */ +#define Eind 2 /* indirect address (jump, call) */ +#define Ew 3 /* address, word size */ +#define Eb 4 /* address, byte size */ +#define R 5 /* register, in 'reg' field */ +#define Rw 6 /* word register, in 'reg' field */ +#define Ri 7 /* register in instruction */ +#define S 8 /* segment reg, in 'reg' field */ +#define Si 9 /* segment reg, in instruction */ +#define A 10 /* accumulator */ +#define BX 11 /* (bx) */ +#define CL 12 /* cl, for shifts */ +#define DX 13 /* dx, for IO */ +#define SI 14 /* si */ +#define DI 15 /* di */ +#define CR 16 /* control register */ +#define DR 17 /* debug register */ +#define TR 18 /* test register */ +#define I 19 /* immediate, unsigned */ +#define Is 20 /* immediate, signed */ +#define Ib 21 /* byte immediate, unsigned */ +#define Ibs 22 /* byte immediate, signed */ +#define Iw 23 /* word immediate, unsigned */ +#define Il 24 /* long immediate */ +#define O 25 /* direct address */ +#define Db 26 /* byte displacement from EIP */ +#define Dl 27 /* long displacement from EIP */ +#define o1 28 /* constant 1 */ +#define o3 29 /* constant 3 */ +#define OS 30 /* immediate offset/segment */ +#define ST 31 /* FP stack top */ +#define STI 32 /* FP stack */ +#define X 33 /* extended FP op */ +#define XA 34 /* for 'fstcw %ax' */ + +struct inst { + char * i_name; /* name */ + short i_has_modrm; /* has regmodrm byte */ + short i_size; /* operand size */ + int i_mode; /* addressing modes */ + char * i_extra; /* pointer to extra opcode table */ +}; + +#define op1(x) (x) +#define op2(x,y) ((x)|((y)<<8)) +#define op3(x,y,z) ((x)|((y)<<8)|((z)<<16)) + +struct finst { + char * f_name; /* name for memory instruction */ + int f_size; /* size for memory instruction */ + int f_rrmode; /* mode for rr instruction */ + char * f_rrname; /* name for rr instruction + (or pointer to table) */ +}; + +char * db_Grp6[] = { + "sldt", + "str", + "lldt", + "ltr", + "verr", + "verw", + "", + "" +}; + +char * db_Grp7[] = { + "sgdt", + "sidt", + "lgdt", + "lidt", + "smsw", + "", + "lmsw", + "invlpg" +}; + +char * db_Grp8[] = { + "", + "", + "", + "", + "bt", + "bts", + "btr", + "btc" +}; + +struct inst db_inst_0f0x[] = { +/*00*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp6 }, +/*01*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp7 }, +/*02*/ { "lar", TRUE, LONG, op2(E,R), 0 }, +/*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 }, +/*04*/ { "", FALSE, NONE, 0, 0 }, +/*05*/ { "", FALSE, NONE, 0, 0 }, +/*06*/ { "clts", FALSE, NONE, 0, 0 }, +/*07*/ { "", FALSE, NONE, 0, 0 }, + +/*08*/ { "invd", FALSE, NONE, 0, 0 }, +/*09*/ { "wbinvd",FALSE, NONE, 0, 0 }, +/*0a*/ { "", FALSE, NONE, 0, 0 }, +/*0b*/ { "", FALSE, NONE, 0, 0 }, +/*0c*/ { "", FALSE, NONE, 0, 0 }, +/*0d*/ { "", FALSE, NONE, 0, 0 }, +/*0e*/ { "", FALSE, NONE, 0, 0 }, +/*0f*/ { "", FALSE, NONE, 0, 0 }, +}; + +struct inst db_inst_0f2x[] = { +/*20*/ { "mov", TRUE, LONG, op2(CR,E), 0 }, /* use E for reg */ +/*21*/ { "mov", TRUE, LONG, op2(DR,E), 0 }, /* since mod == 11 */ +/*22*/ { "mov", TRUE, LONG, op2(E,CR), 0 }, +/*23*/ { "mov", TRUE, LONG, op2(E,DR), 0 }, +/*24*/ { "mov", TRUE, LONG, op2(TR,E), 0 }, +/*25*/ { "", FALSE, NONE, 0, 0 }, +/*26*/ { "mov", TRUE, LONG, op2(E,TR), 0 }, +/*27*/ { "", FALSE, NONE, 0, 0 }, + +/*28*/ { "", FALSE, NONE, 0, 0 }, +/*29*/ { "", FALSE, NONE, 0, 0 }, +/*2a*/ { "", FALSE, NONE, 0, 0 }, +/*2b*/ { "", FALSE, NONE, 0, 0 }, +/*2c*/ { "", FALSE, NONE, 0, 0 }, +/*2d*/ { "", FALSE, NONE, 0, 0 }, +/*2e*/ { "", FALSE, NONE, 0, 0 }, +/*2f*/ { "", FALSE, NONE, 0, 0 }, +}; + +struct inst db_inst_0f8x[] = { +/*80*/ { "jo", FALSE, NONE, op1(Dl), 0 }, +/*81*/ { "jno", FALSE, NONE, op1(Dl), 0 }, +/*82*/ { "jb", FALSE, NONE, op1(Dl), 0 }, +/*83*/ { "jnb", FALSE, NONE, op1(Dl), 0 }, +/*84*/ { "jz", FALSE, NONE, op1(Dl), 0 }, +/*85*/ { "jnz", FALSE, NONE, op1(Dl), 0 }, +/*86*/ { "jbe", FALSE, NONE, op1(Dl), 0 }, +/*87*/ { "jnbe", FALSE, NONE, op1(Dl), 0 }, + +/*88*/ { "js", FALSE, NONE, op1(Dl), 0 }, +/*89*/ { "jns", FALSE, NONE, op1(Dl), 0 }, +/*8a*/ { "jp", FALSE, NONE, op1(Dl), 0 }, +/*8b*/ { "jnp", FALSE, NONE, op1(Dl), 0 }, +/*8c*/ { "jl", FALSE, NONE, op1(Dl), 0 }, +/*8d*/ { "jnl", FALSE, NONE, op1(Dl), 0 }, +/*8e*/ { "jle", FALSE, NONE, op1(Dl), 0 }, +/*8f*/ { "jnle", FALSE, NONE, op1(Dl), 0 }, +}; + +struct inst db_inst_0f9x[] = { +/*90*/ { "seto", TRUE, NONE, op1(Eb), 0 }, +/*91*/ { "setno", TRUE, NONE, op1(Eb), 0 }, +/*92*/ { "setb", TRUE, NONE, op1(Eb), 0 }, +/*93*/ { "setnb", TRUE, NONE, op1(Eb), 0 }, +/*94*/ { "setz", TRUE, NONE, op1(Eb), 0 }, +/*95*/ { "setnz", TRUE, NONE, op1(Eb), 0 }, +/*96*/ { "setbe", TRUE, NONE, op1(Eb), 0 }, +/*97*/ { "setnbe",TRUE, NONE, op1(Eb), 0 }, + +/*98*/ { "sets", TRUE, NONE, op1(Eb), 0 }, +/*99*/ { "setns", TRUE, NONE, op1(Eb), 0 }, +/*9a*/ { "setp", TRUE, NONE, op1(Eb), 0 }, +/*9b*/ { "setnp", TRUE, NONE, op1(Eb), 0 }, +/*9c*/ { "setl", TRUE, NONE, op1(Eb), 0 }, +/*9d*/ { "setnl", TRUE, NONE, op1(Eb), 0 }, +/*9e*/ { "setle", TRUE, NONE, op1(Eb), 0 }, +/*9f*/ { "setnle",TRUE, NONE, op1(Eb), 0 }, +}; + +struct inst db_inst_0fax[] = { +/*a0*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*a1*/ { "pop", FALSE, NONE, op1(Si), 0 }, +/*a2*/ { "", FALSE, NONE, 0, 0 }, +/*a3*/ { "bt", TRUE, LONG, op2(E,R), 0 }, +/*a4*/ { "shld", TRUE, LONG, op3(Ib,E,R), 0 }, +/*a5*/ { "shld", TRUE, LONG, op3(CL,E,R), 0 }, +/*a6*/ { "", FALSE, NONE, 0, 0 }, +/*a7*/ { "", FALSE, NONE, 0, 0 }, + +/*a8*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*a9*/ { "pop", FALSE, NONE, op1(Si), 0 }, +/*aa*/ { "", FALSE, NONE, 0, 0 }, +/*ab*/ { "bts", TRUE, LONG, op2(E,R), 0 }, +/*ac*/ { "shrd", TRUE, LONG, op3(Ib,E,R), 0 }, +/*ad*/ { "shrd", TRUE, LONG, op3(CL,E,R), 0 }, +/*a6*/ { "", FALSE, NONE, 0, 0 }, +/*a7*/ { "imul", TRUE, LONG, op2(E,R), 0 }, +}; + +struct inst db_inst_0fbx[] = { +/*b0*/ { "", FALSE, NONE, 0, 0 }, +/*b1*/ { "", FALSE, NONE, 0, 0 }, +/*b2*/ { "lss", TRUE, LONG, op2(E, R), 0 }, +/*b3*/ { "bts", TRUE, LONG, op2(R, E), 0 }, +/*b4*/ { "lfs", TRUE, LONG, op2(E, R), 0 }, +/*b5*/ { "lgs", TRUE, LONG, op2(E, R), 0 }, +/*b6*/ { "movzb", TRUE, LONG, op2(E, R), 0 }, +/*b7*/ { "movzw", TRUE, LONG, op2(E, R), 0 }, + +/*b8*/ { "", FALSE, NONE, 0, 0 }, +/*b9*/ { "", FALSE, NONE, 0, 0 }, +/*ba*/ { "", TRUE, LONG, op2(Is, E), (char *)db_Grp8 }, +/*bb*/ { "btc", TRUE, LONG, op2(R, E), 0 }, +/*bc*/ { "bsf", TRUE, LONG, op2(E, R), 0 }, +/*bd*/ { "bsr", TRUE, LONG, op2(E, R), 0 }, +/*be*/ { "movsb", TRUE, LONG, op2(E, R), 0 }, +/*bf*/ { "movsw", TRUE, LONG, op2(E, R), 0 }, +}; + +struct inst db_inst_0fcx[] = { +/*c0*/ { "xadd", TRUE, BYTE, op2(R, E), 0 }, +/*c1*/ { "xadd", TRUE, LONG, op2(R, E), 0 }, +/*c2*/ { "", FALSE, NONE, 0, 0 }, +/*c3*/ { "", FALSE, NONE, 0, 0 }, +/*c4*/ { "", FALSE, NONE, 0, 0 }, +/*c5*/ { "", FALSE, NONE, 0, 0 }, +/*c6*/ { "", FALSE, NONE, 0, 0 }, +/*c7*/ { "", FALSE, NONE, 0, 0 }, +/*c8*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*c9*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*ca*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*cb*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*cc*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*cd*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*ce*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*cf*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +}; + +struct inst db_inst_0fdx[] = { +/*c0*/ { "cmpxchg",TRUE, BYTE, op2(R, E), 0 }, +/*c1*/ { "cmpxchg",TRUE, LONG, op2(R, E), 0 }, +/*c2*/ { "", FALSE, NONE, 0, 0 }, +/*c3*/ { "", FALSE, NONE, 0, 0 }, +/*c4*/ { "", FALSE, NONE, 0, 0 }, +/*c5*/ { "", FALSE, NONE, 0, 0 }, +/*c6*/ { "", FALSE, NONE, 0, 0 }, +/*c7*/ { "", FALSE, NONE, 0, 0 }, +/*c8*/ { "", FALSE, NONE, 0, 0 }, +/*c9*/ { "", FALSE, NONE, 0, 0 }, +/*ca*/ { "", FALSE, NONE, 0, 0 }, +/*cb*/ { "", FALSE, NONE, 0, 0 }, +/*cc*/ { "", FALSE, NONE, 0, 0 }, +/*cd*/ { "", FALSE, NONE, 0, 0 }, +/*ce*/ { "", FALSE, NONE, 0, 0 }, +/*cf*/ { "", FALSE, NONE, 0, 0 }, +}; + +struct inst *db_inst_0f[] = { + db_inst_0f0x, + 0, + db_inst_0f2x, + 0, + 0, + 0, + 0, + 0, + db_inst_0f8x, + db_inst_0f9x, + db_inst_0fax, + db_inst_0fbx, + db_inst_0fcx, + db_inst_0fdx, + 0, + 0 +}; + +char * db_Esc92[] = { + "fnop", "", "", "", "", "", "", "" +}; +char * db_Esc93[] = { + "", "", "", "", "", "", "", "" +}; +char * db_Esc94[] = { + "fchs", "fabs", "", "", "ftst", "fxam", "", "" +}; +char * db_Esc95[] = { + "fld1", "fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","" +}; +char * db_Esc96[] = { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp", + "fincstp" +}; +char * db_Esc97[] = { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos" +}; + +char * db_Esca4[] = { + "", "fucompp","", "", "", "", "", "" +}; + +char * db_Escb4[] = { + "", "", "fnclex","fninit","", "", "", "" +}; + +char * db_Esce3[] = { + "", "fcompp","", "", "", "", "", "" +}; + +char * db_Escf4[] = { + "fnstsw","", "", "", "", "", "", "" +}; + +struct finst db_Esc8[] = { +/*0*/ { "fadd", SNGL, op2(STI,ST), 0 }, +/*1*/ { "fmul", SNGL, op2(STI,ST), 0 }, +/*2*/ { "fcom", SNGL, op2(STI,ST), 0 }, +/*3*/ { "fcomp", SNGL, op2(STI,ST), 0 }, +/*4*/ { "fsub", SNGL, op2(STI,ST), 0 }, +/*5*/ { "fsubr", SNGL, op2(STI,ST), 0 }, +/*6*/ { "fdiv", SNGL, op2(STI,ST), 0 }, +/*7*/ { "fdivr", SNGL, op2(STI,ST), 0 }, +}; + +struct finst db_Esc9[] = { +/*0*/ { "fld", SNGL, op1(STI), 0 }, +/*1*/ { "", NONE, op1(STI), "fxch" }, +/*2*/ { "fst", SNGL, op1(X), (char *)db_Esc92 }, +/*3*/ { "fstp", SNGL, op1(X), (char *)db_Esc93 }, +/*4*/ { "fldenv", NONE, op1(X), (char *)db_Esc94 }, +/*5*/ { "fldcw", NONE, op1(X), (char *)db_Esc95 }, +/*6*/ { "fnstenv",NONE, op1(X), (char *)db_Esc96 }, +/*7*/ { "fnstcw", NONE, op1(X), (char *)db_Esc97 }, +}; + +struct finst db_Esca[] = { +/*0*/ { "fiadd", WORD, 0, 0 }, +/*1*/ { "fimul", WORD, 0, 0 }, +/*2*/ { "ficom", WORD, 0, 0 }, +/*3*/ { "ficomp", WORD, 0, 0 }, +/*4*/ { "fisub", WORD, op1(X), (char *)db_Esca4 }, +/*5*/ { "fisubr", WORD, 0, 0 }, +/*6*/ { "fidiv", WORD, 0, 0 }, +/*7*/ { "fidivr", WORD, 0, 0 } +}; + +struct finst db_Escb[] = { +/*0*/ { "fild", WORD, 0, 0 }, +/*1*/ { "", NONE, 0, 0 }, +/*2*/ { "fist", WORD, 0, 0 }, +/*3*/ { "fistp", WORD, 0, 0 }, +/*4*/ { "", WORD, op1(X), (char *)db_Escb4 }, +/*5*/ { "fld", EXTR, 0, 0 }, +/*6*/ { "", WORD, 0, 0 }, +/*7*/ { "fstp", EXTR, 0, 0 }, +}; + +struct finst db_Escc[] = { +/*0*/ { "fadd", DBLR, op2(ST,STI), 0 }, +/*1*/ { "fmul", DBLR, op2(ST,STI), 0 }, +/*2*/ { "fcom", DBLR, op2(ST,STI), 0 }, +/*3*/ { "fcomp", DBLR, op2(ST,STI), 0 }, +/*4*/ { "fsub", DBLR, op2(ST,STI), "fsubr" }, +/*5*/ { "fsubr", DBLR, op2(ST,STI), "fsub" }, +/*6*/ { "fdiv", DBLR, op2(ST,STI), "fdivr" }, +/*7*/ { "fdivr", DBLR, op2(ST,STI), "fdiv" }, +}; + +struct finst db_Escd[] = { +/*0*/ { "fld", DBLR, op1(STI), "ffree" }, +/*1*/ { "", NONE, 0, 0 }, +/*2*/ { "fst", DBLR, op1(STI), 0 }, +/*3*/ { "fstp", DBLR, op1(STI), 0 }, +/*4*/ { "frstor", NONE, op1(STI), "fucom" }, +/*5*/ { "", NONE, op1(STI), "fucomp" }, +/*6*/ { "fnsave", NONE, 0, 0 }, +/*7*/ { "fnstsw", NONE, 0, 0 }, +}; + +struct finst db_Esce[] = { +/*0*/ { "fiadd", LONG, op2(ST,STI), "faddp" }, +/*1*/ { "fimul", LONG, op2(ST,STI), "fmulp" }, +/*2*/ { "ficom", LONG, 0, 0 }, +/*3*/ { "ficomp", LONG, op1(X), (char *)db_Esce3 }, +/*4*/ { "fisub", LONG, op2(ST,STI), "fsubrp" }, +/*5*/ { "fisubr", LONG, op2(ST,STI), "fsubp" }, +/*6*/ { "fidiv", LONG, op2(ST,STI), "fdivrp" }, +/*7*/ { "fidivr", LONG, op2(ST,STI), "fdivp" }, +}; + +struct finst db_Escf[] = { +/*0*/ { "fild", LONG, 0, 0 }, +/*1*/ { "", LONG, 0, 0 }, +/*2*/ { "fist", LONG, 0, 0 }, +/*3*/ { "fistp", LONG, 0, 0 }, +/*4*/ { "fbld", NONE, op1(XA), (char *)db_Escf4 }, +/*5*/ { "fld", QUAD, 0, 0 }, +/*6*/ { "fbstp", NONE, 0, 0 }, +/*7*/ { "fstp", QUAD, 0, 0 }, +}; + +struct finst *db_Esc_inst[] = { + db_Esc8, db_Esc9, db_Esca, db_Escb, + db_Escc, db_Escd, db_Esce, db_Escf +}; + +char * db_Grp1[] = { + "add", + "or", + "adc", + "sbb", + "and", + "sub", + "xor", + "cmp" +}; + +char * db_Grp2[] = { + "rol", + "ror", + "rcl", + "rcr", + "shl", + "shr", + "shl", + "sar" +}; + +struct inst db_Grp3[] = { + { "test", TRUE, NONE, op2(I,E), 0 }, + { "test", TRUE, NONE, op2(I,E), 0 }, + { "not", TRUE, NONE, op1(E), 0 }, + { "neg", TRUE, NONE, op1(E), 0 }, + { "mul", TRUE, NONE, op2(E,A), 0 }, + { "imul", TRUE, NONE, op2(E,A), 0 }, + { "div", TRUE, NONE, op2(E,A), 0 }, + { "idiv", TRUE, NONE, op2(E,A), 0 }, +}; + +struct inst db_Grp4[] = { + { "inc", TRUE, BYTE, op1(E), 0 }, + { "dec", TRUE, BYTE, op1(E), 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 } +}; + +struct inst db_Grp5[] = { + { "inc", TRUE, LONG, op1(E), 0 }, + { "dec", TRUE, LONG, op1(E), 0 }, + { "call", TRUE, NONE, op1(Eind),0 }, + { "lcall", TRUE, NONE, op1(Eind),0 }, + { "jmp", TRUE, NONE, op1(Eind),0 }, + { "ljmp", TRUE, NONE, op1(Eind),0 }, + { "push", TRUE, LONG, op1(E), 0 }, + { "", TRUE, NONE, 0, 0 } +}; + +struct inst db_inst_table[256] = { +/*00*/ { "add", TRUE, BYTE, op2(R, E), 0 }, +/*01*/ { "add", TRUE, LONG, op2(R, E), 0 }, +/*02*/ { "add", TRUE, BYTE, op2(E, R), 0 }, +/*03*/ { "add", TRUE, LONG, op2(E, R), 0 }, +/*04*/ { "add", FALSE, BYTE, op2(Is, A), 0 }, +/*05*/ { "add", FALSE, LONG, op2(Is, A), 0 }, +/*06*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*07*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*08*/ { "or", TRUE, BYTE, op2(R, E), 0 }, +/*09*/ { "or", TRUE, LONG, op2(R, E), 0 }, +/*0a*/ { "or", TRUE, BYTE, op2(E, R), 0 }, +/*0b*/ { "or", TRUE, LONG, op2(E, R), 0 }, +/*0c*/ { "or", FALSE, BYTE, op2(I, A), 0 }, +/*0d*/ { "or", FALSE, LONG, op2(I, A), 0 }, +/*0e*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*0f*/ { "", FALSE, NONE, 0, 0 }, + +/*10*/ { "adc", TRUE, BYTE, op2(R, E), 0 }, +/*11*/ { "adc", TRUE, LONG, op2(R, E), 0 }, +/*12*/ { "adc", TRUE, BYTE, op2(E, R), 0 }, +/*13*/ { "adc", TRUE, LONG, op2(E, R), 0 }, +/*14*/ { "adc", FALSE, BYTE, op2(Is, A), 0 }, +/*15*/ { "adc", FALSE, LONG, op2(Is, A), 0 }, +/*16*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*17*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*18*/ { "sbb", TRUE, BYTE, op2(R, E), 0 }, +/*19*/ { "sbb", TRUE, LONG, op2(R, E), 0 }, +/*1a*/ { "sbb", TRUE, BYTE, op2(E, R), 0 }, +/*1b*/ { "sbb", TRUE, LONG, op2(E, R), 0 }, +/*1c*/ { "sbb", FALSE, BYTE, op2(Is, A), 0 }, +/*1d*/ { "sbb", FALSE, LONG, op2(Is, A), 0 }, +/*1e*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*1f*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*20*/ { "and", TRUE, BYTE, op2(R, E), 0 }, +/*21*/ { "and", TRUE, LONG, op2(R, E), 0 }, +/*22*/ { "and", TRUE, BYTE, op2(E, R), 0 }, +/*23*/ { "and", TRUE, LONG, op2(E, R), 0 }, +/*24*/ { "and", FALSE, BYTE, op2(I, A), 0 }, +/*25*/ { "and", FALSE, LONG, op2(I, A), 0 }, +/*26*/ { "", FALSE, NONE, 0, 0 }, +/*27*/ { "aaa", FALSE, NONE, 0, 0 }, + +/*28*/ { "sub", TRUE, BYTE, op2(R, E), 0 }, +/*29*/ { "sub", TRUE, LONG, op2(R, E), 0 }, +/*2a*/ { "sub", TRUE, BYTE, op2(E, R), 0 }, +/*2b*/ { "sub", TRUE, LONG, op2(E, R), 0 }, +/*2c*/ { "sub", FALSE, BYTE, op2(Is, A), 0 }, +/*2d*/ { "sub", FALSE, LONG, op2(Is, A), 0 }, +/*2e*/ { "", FALSE, NONE, 0, 0 }, +/*2f*/ { "das", FALSE, NONE, 0, 0 }, + +/*30*/ { "xor", TRUE, BYTE, op2(R, E), 0 }, +/*31*/ { "xor", TRUE, LONG, op2(R, E), 0 }, +/*32*/ { "xor", TRUE, BYTE, op2(E, R), 0 }, +/*33*/ { "xor", TRUE, LONG, op2(E, R), 0 }, +/*34*/ { "xor", FALSE, BYTE, op2(I, A), 0 }, +/*35*/ { "xor", FALSE, LONG, op2(I, A), 0 }, +/*36*/ { "", FALSE, NONE, 0, 0 }, +/*37*/ { "daa", FALSE, NONE, 0, 0 }, + +/*38*/ { "cmp", TRUE, BYTE, op2(R, E), 0 }, +/*39*/ { "cmp", TRUE, LONG, op2(R, E), 0 }, +/*3a*/ { "cmp", TRUE, BYTE, op2(E, R), 0 }, +/*3b*/ { "cmp", TRUE, LONG, op2(E, R), 0 }, +/*3c*/ { "cmp", FALSE, BYTE, op2(Is, A), 0 }, +/*3d*/ { "cmp", FALSE, LONG, op2(Is, A), 0 }, +/*3e*/ { "", FALSE, NONE, 0, 0 }, +/*3f*/ { "aas", FALSE, NONE, 0, 0 }, + +/*40*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*41*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*42*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*43*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*44*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*45*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*46*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*47*/ { "inc", FALSE, LONG, op1(Ri), 0 }, + +/*48*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*49*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4a*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4b*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4c*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4d*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4e*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4f*/ { "dec", FALSE, LONG, op1(Ri), 0 }, + +/*50*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*51*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*52*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*53*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*54*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*55*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*56*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*57*/ { "push", FALSE, LONG, op1(Ri), 0 }, + +/*58*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*59*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5a*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5b*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5c*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5d*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5e*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5f*/ { "pop", FALSE, LONG, op1(Ri), 0 }, + +/*60*/ { "pusha", FALSE, LONG, 0, 0 }, +/*61*/ { "popa", FALSE, LONG, 0, 0 }, +/*62*/ { "bound", TRUE, LONG, op2(E, R), 0 }, +/*63*/ { "arpl", TRUE, NONE, op2(Ew,Rw), 0 }, + +/*64*/ { "", FALSE, NONE, 0, 0 }, +/*65*/ { "", FALSE, NONE, 0, 0 }, +/*66*/ { "", FALSE, NONE, 0, 0 }, +/*67*/ { "", FALSE, NONE, 0, 0 }, + +/*68*/ { "push", FALSE, LONG, op1(I), 0 }, +/*69*/ { "imul", TRUE, LONG, op3(I,E,R), 0 }, +/*6a*/ { "push", FALSE, LONG, op1(Ib), 0 }, +/*6b*/ { "imul", TRUE, LONG, op3(Ibs,E,R),0 }, +/*6c*/ { "ins", FALSE, BYTE, op2(DX, DI), 0 }, +/*6d*/ { "ins", FALSE, LONG, op2(DX, DI), 0 }, +/*6e*/ { "outs", FALSE, BYTE, op2(SI, DX), 0 }, +/*6f*/ { "outs", FALSE, LONG, op2(SI, DX), 0 }, + +/*70*/ { "jo", FALSE, NONE, op1(Db), 0 }, +/*71*/ { "jno", FALSE, NONE, op1(Db), 0 }, +/*72*/ { "jb", FALSE, NONE, op1(Db), 0 }, +/*73*/ { "jnb", FALSE, NONE, op1(Db), 0 }, +/*74*/ { "jz", FALSE, NONE, op1(Db), 0 }, +/*75*/ { "jnz", FALSE, NONE, op1(Db), 0 }, +/*76*/ { "jbe", FALSE, NONE, op1(Db), 0 }, +/*77*/ { "jnbe", FALSE, NONE, op1(Db), 0 }, + +/*78*/ { "js", FALSE, NONE, op1(Db), 0 }, +/*79*/ { "jns", FALSE, NONE, op1(Db), 0 }, +/*7a*/ { "jp", FALSE, NONE, op1(Db), 0 }, +/*7b*/ { "jnp", FALSE, NONE, op1(Db), 0 }, +/*7c*/ { "jl", FALSE, NONE, op1(Db), 0 }, +/*7d*/ { "jnl", FALSE, NONE, op1(Db), 0 }, +/*7e*/ { "jle", FALSE, NONE, op1(Db), 0 }, +/*7f*/ { "jnle", FALSE, NONE, op1(Db), 0 }, + +/*80*/ { "", TRUE, BYTE, op2(I, E), (char *)db_Grp1 }, +/*81*/ { "", TRUE, LONG, op2(I, E), (char *)db_Grp1 }, +/*82*/ { "", TRUE, BYTE, op2(Is,E), (char *)db_Grp1 }, +/*83*/ { "", TRUE, LONG, op2(Ibs,E), (char *)db_Grp1 }, +/*84*/ { "test", TRUE, BYTE, op2(R, E), 0 }, +/*85*/ { "test", TRUE, LONG, op2(R, E), 0 }, +/*86*/ { "xchg", TRUE, BYTE, op2(R, E), 0 }, +/*87*/ { "xchg", TRUE, LONG, op2(R, E), 0 }, + +/*88*/ { "mov", TRUE, BYTE, op2(R, E), 0 }, +/*89*/ { "mov", TRUE, LONG, op2(R, E), 0 }, +/*8a*/ { "mov", TRUE, BYTE, op2(E, R), 0 }, +/*8b*/ { "mov", TRUE, LONG, op2(E, R), 0 }, +/*8c*/ { "mov", TRUE, NONE, op2(S, Ew), 0 }, +/*8d*/ { "lea", TRUE, LONG, op2(E, R), 0 }, +/*8e*/ { "mov", TRUE, NONE, op2(Ew, S), 0 }, +/*8f*/ { "pop", TRUE, LONG, op1(E), 0 }, + +/*90*/ { "nop", FALSE, NONE, 0, 0 }, +/*91*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*92*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*93*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*94*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*95*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*96*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*97*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, + +/*98*/ { "cbw", FALSE, SDEP, 0, "cwde" }, /* cbw/cwde */ +/*99*/ { "cwd", FALSE, SDEP, 0, "cdq" }, /* cwd/cdq */ +/*9a*/ { "lcall", FALSE, NONE, op1(OS), 0 }, +/*9b*/ { "wait", FALSE, NONE, 0, 0 }, +/*9c*/ { "pushf", FALSE, LONG, 0, 0 }, +/*9d*/ { "popf", FALSE, LONG, 0, 0 }, +/*9e*/ { "sahf", FALSE, NONE, 0, 0 }, +/*9f*/ { "lahf", FALSE, NONE, 0, 0 }, + +/*a0*/ { "mov", FALSE, BYTE, op2(O, A), 0 }, +/*a1*/ { "mov", FALSE, LONG, op2(O, A), 0 }, +/*a2*/ { "mov", FALSE, BYTE, op2(A, O), 0 }, +/*a3*/ { "mov", FALSE, LONG, op2(A, O), 0 }, +/*a4*/ { "movs", FALSE, BYTE, op2(SI,DI), 0 }, +/*a5*/ { "movs", FALSE, LONG, op2(SI,DI), 0 }, +/*a6*/ { "cmps", FALSE, BYTE, op2(SI,DI), 0 }, +/*a7*/ { "cmps", FALSE, LONG, op2(SI,DI), 0 }, + +/*a8*/ { "test", FALSE, BYTE, op2(I, A), 0 }, +/*a9*/ { "test", FALSE, LONG, op2(I, A), 0 }, +/*aa*/ { "stos", FALSE, BYTE, op1(DI), 0 }, +/*ab*/ { "stos", FALSE, LONG, op1(DI), 0 }, +/*ac*/ { "ldos", FALSE, BYTE, op1(SI), 0 }, +/*ad*/ { "ldos", FALSE, LONG, op1(SI), 0 }, +/*ae*/ { "scas", FALSE, BYTE, op1(SI), 0 }, +/*af*/ { "scas", FALSE, LONG, op1(SI), 0 }, + +/*b0*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b1*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b2*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b3*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b4*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b5*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b6*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b7*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, + +/*b8*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*b9*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*ba*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bb*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bc*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bd*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*be*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bf*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, + +/*c0*/ { "", TRUE, BYTE, op2(Ib, E), (char *)db_Grp2 }, +/*c1*/ { "", TRUE, LONG, op2(Ib, E), (char *)db_Grp2 }, +/*c2*/ { "ret", FALSE, NONE, op1(Iw), 0 }, +/*c3*/ { "ret", FALSE, NONE, 0, 0 }, +/*c4*/ { "les", TRUE, LONG, op2(E, R), 0 }, +/*c5*/ { "lds", TRUE, LONG, op2(E, R), 0 }, +/*c6*/ { "mov", TRUE, BYTE, op2(I, E), 0 }, +/*c7*/ { "mov", TRUE, LONG, op2(I, E), 0 }, + +/*c8*/ { "enter", FALSE, NONE, op2(Ib, Iw), 0 }, +/*c9*/ { "leave", FALSE, NONE, 0, 0 }, +/*ca*/ { "lret", FALSE, NONE, op1(Iw), 0 }, +/*cb*/ { "lret", FALSE, NONE, 0, 0 }, +/*cc*/ { "int", FALSE, NONE, op1(o3), 0 }, +/*cd*/ { "int", FALSE, NONE, op1(Ib), 0 }, +/*ce*/ { "into", FALSE, NONE, 0, 0 }, +/*cf*/ { "iret", FALSE, NONE, 0, 0 }, + +/*d0*/ { "", TRUE, BYTE, op2(o1, E), (char *)db_Grp2 }, +/*d1*/ { "", TRUE, LONG, op2(o1, E), (char *)db_Grp2 }, +/*d2*/ { "", TRUE, BYTE, op2(CL, E), (char *)db_Grp2 }, +/*d3*/ { "", TRUE, LONG, op2(CL, E), (char *)db_Grp2 }, +/*d4*/ { "aam", TRUE, NONE, 0, 0 }, +/*d5*/ { "aad", TRUE, NONE, 0, 0 }, +/*d6*/ { "", FALSE, NONE, 0, 0 }, +/*d7*/ { "xlat", FALSE, BYTE, op1(BX), 0 }, + +/*d8*/ { "", TRUE, NONE, 0, (char *)db_Esc8 }, +/*d9*/ { "", TRUE, NONE, 0, (char *)db_Esc9 }, +/*da*/ { "", TRUE, NONE, 0, (char *)db_Esca }, +/*db*/ { "", TRUE, NONE, 0, (char *)db_Escb }, +/*dc*/ { "", TRUE, NONE, 0, (char *)db_Escc }, +/*dd*/ { "", TRUE, NONE, 0, (char *)db_Escd }, +/*de*/ { "", TRUE, NONE, 0, (char *)db_Esce }, +/*df*/ { "", TRUE, NONE, 0, (char *)db_Escf }, + +/*e0*/ { "loopne",FALSE, NONE, op1(Db), 0 }, +/*e1*/ { "loope", FALSE, NONE, op1(Db), 0 }, +/*e2*/ { "loop", FALSE, NONE, op1(Db), 0 }, +/*e3*/ { "jcxz", FALSE, SDEP, op1(Db), "jecxz" }, +/*e4*/ { "in", FALSE, BYTE, op2(Ib, A), 0 }, +/*e5*/ { "in", FALSE, LONG, op2(Ib, A) , 0 }, +/*e6*/ { "out", FALSE, BYTE, op2(A, Ib), 0 }, +/*e7*/ { "out", FALSE, LONG, op2(A, Ib) , 0 }, + +/*e8*/ { "call", FALSE, NONE, op1(Dl), 0 }, +/*e9*/ { "jmp", FALSE, NONE, op1(Dl), 0 }, +/*ea*/ { "ljmp", FALSE, NONE, op1(OS), 0 }, +/*eb*/ { "jmp", FALSE, NONE, op1(Db), 0 }, +/*ec*/ { "in", FALSE, BYTE, op2(DX, A), 0 }, +/*ed*/ { "in", FALSE, LONG, op2(DX, A) , 0 }, +/*ee*/ { "out", FALSE, BYTE, op2(A, DX), 0 }, +/*ef*/ { "out", FALSE, LONG, op2(A, DX) , 0 }, + +/*f0*/ { "", FALSE, NONE, 0, 0 }, +/*f1*/ { "", FALSE, NONE, 0, 0 }, +/*f2*/ { "", FALSE, NONE, 0, 0 }, +/*f3*/ { "", FALSE, NONE, 0, 0 }, +/*f4*/ { "hlt", FALSE, NONE, 0, 0 }, +/*f5*/ { "cmc", FALSE, NONE, 0, 0 }, +/*f6*/ { "", TRUE, BYTE, 0, (char *)db_Grp3 }, +/*f7*/ { "", TRUE, LONG, 0, (char *)db_Grp3 }, + +/*f8*/ { "clc", FALSE, NONE, 0, 0 }, +/*f9*/ { "stc", FALSE, NONE, 0, 0 }, +/*fa*/ { "cli", FALSE, NONE, 0, 0 }, +/*fb*/ { "sti", FALSE, NONE, 0, 0 }, +/*fc*/ { "cld", FALSE, NONE, 0, 0 }, +/*fd*/ { "std", FALSE, NONE, 0, 0 }, +/*fe*/ { "", TRUE, NONE, 0, (char *)db_Grp4 }, +/*ff*/ { "", TRUE, NONE, 0, (char *)db_Grp5 }, +}; + +struct inst db_bad_inst = + { "???", FALSE, NONE, 0, 0 } +; + +#define f_mod(byte) ((byte)>>6) +#define f_reg(byte) (((byte)>>3)&0x7) +#define f_rm(byte) ((byte)&0x7) + +#define sib_ss(byte) ((byte)>>6) +#define sib_index(byte) (((byte)>>3)&0x7) +#define sib_base(byte) ((byte)&0x7) + +struct i_addr { + int is_reg; /* if reg, reg number is in 'disp' */ + int disp; + char * base; + char * index; + int ss; +}; + +char * db_index_reg_16[8] = { + "%bx,%si", + "%bx,%di", + "%bp,%si", + "%bp,%di", + "%si", + "%di", + "%bp", + "%bx" +}; + +char * db_reg[3][8] = { + "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", + "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", + "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi" +}; + +char * db_seg_reg[8] = { + "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "", "" +}; + +/* + * lengths for size attributes + */ +int db_lengths[] = { + 1, /* BYTE */ + 2, /* WORD */ + 4, /* LONG */ + 8, /* QUAD */ + 4, /* SNGL */ + 8, /* DBLR */ + 10, /* EXTR */ +}; + +#define get_value_inc(result, loc, size, is_signed) \ + result = db_get_value((loc), (size), (is_signed)); \ + (loc) += (size); + +/* + * Read address at location and return updated location. + */ +db_addr_t +db_read_address(loc, short_addr, regmodrm, addrp) + db_addr_t loc; + int short_addr; + int regmodrm; + struct i_addr *addrp; /* out */ +{ + int mod, rm, sib, index, ss, disp; + + mod = f_mod(regmodrm); + rm = f_rm(regmodrm); + + if (mod == 3) { + addrp->is_reg = TRUE; + addrp->disp = rm; + return (loc); + } + addrp->is_reg = FALSE; + addrp->index = 0; + + if (short_addr) { + addrp->index = 0; + addrp->ss = 0; + switch (mod) { + case 0: + if (rm == 6) { + get_value_inc(disp, loc, 2, TRUE); + addrp->disp = disp; + addrp->base = 0; + } + else { + addrp->disp = 0; + addrp->base = db_index_reg_16[rm]; + } + break; + case 1: + get_value_inc(disp, loc, 1, TRUE); + addrp->disp = disp; + addrp->base = db_index_reg_16[rm]; + break; + case 2: + get_value_inc(disp, loc, 2, TRUE); + addrp->disp = disp; + addrp->base = db_index_reg_16[rm]; + break; + } + } + else { + if (mod != 3 && rm == 4) { + get_value_inc(sib, loc, 1, FALSE); + rm = sib_base(sib); + index = sib_index(sib); + if (index != 4) + addrp->index = db_reg[LONG][index]; + addrp->ss = sib_ss(sib); + } + + switch (mod) { + case 0: + if (rm == 5) { + get_value_inc(addrp->disp, loc, 4, FALSE); + addrp->base = 0; + } + else { + addrp->disp = 0; + addrp->base = db_reg[LONG][rm]; + } + break; + + case 1: + get_value_inc(disp, loc, 1, TRUE); + addrp->disp = disp; + addrp->base = db_reg[LONG][rm]; + break; + + case 2: + get_value_inc(disp, loc, 4, FALSE); + addrp->disp = disp; + addrp->base = db_reg[LONG][rm]; + break; + } + } + return (loc); +} + +void +db_print_address(seg, size, addrp) + char * seg; + int size; + struct i_addr *addrp; +{ + if (addrp->is_reg) { + db_printf("%s", db_reg[size][addrp->disp]); + return; + } + + if (seg) { + db_printf("%s:", seg); + } + + db_printsym((db_addr_t)addrp->disp, DB_STGY_ANY); + if (addrp->base != 0 || addrp->index != 0) { + db_printf("("); + if (addrp->base) + db_printf("%s", addrp->base); + if (addrp->index) + db_printf(",%s,%d", addrp->index, 1<<addrp->ss); + db_printf(")"); + } +} + +/* + * Disassemble floating-point ("escape") instruction + * and return updated location. + */ +db_addr_t +db_disasm_esc(loc, inst, short_addr, size, seg) + db_addr_t loc; + int inst; + int short_addr; + int size; + char * seg; +{ + int regmodrm; + struct finst *fp; + int mod; + struct i_addr address; + char * name; + + get_value_inc(regmodrm, loc, 1, FALSE); + fp = &db_Esc_inst[inst - 0xd8][f_reg(regmodrm)]; + mod = f_mod(regmodrm); + if (mod != 3) { + /* + * Normal address modes. + */ + loc = db_read_address(loc, short_addr, regmodrm, &address); + db_printf(fp->f_name); + switch(fp->f_size) { + case SNGL: + db_printf("s"); + break; + case DBLR: + db_printf("l"); + break; + case EXTR: + db_printf("t"); + break; + case WORD: + db_printf("s"); + break; + case LONG: + db_printf("l"); + break; + case QUAD: + db_printf("q"); + break; + default: + break; + } + db_printf("\t"); + db_print_address(seg, BYTE, &address); + } + else { + /* + * 'reg-reg' - special formats + */ + switch (fp->f_rrmode) { + case op2(ST,STI): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + db_printf("%s\t%%st,%%st(%d)",name,f_rm(regmodrm)); + break; + case op2(STI,ST): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + db_printf("%s\t%%st(%d),%%st",name, f_rm(regmodrm)); + break; + case op1(STI): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + db_printf("%s\t%%st(%d)",name, f_rm(regmodrm)); + break; + case op1(X): + db_printf("%s", ((char **)fp->f_rrname)[f_rm(regmodrm)]); + break; + case op1(XA): + db_printf("%s\t%%ax", + ((char **)fp->f_rrname)[f_rm(regmodrm)]); + break; + default: + db_printf("<bad instruction>"); + break; + } + } + + return (loc); +} + +/* + * Disassemble instruction at 'loc'. 'altfmt' specifies an + * (optional) alternate format. Return address of start of + * next instruction. + */ +db_addr_t +db_disasm(loc, altfmt) + db_addr_t loc; + boolean_t altfmt; +{ + int inst; + int size; + int short_addr; + char * seg; + struct inst * ip; + char * i_name; + int i_size; + int i_mode; + int regmodrm; + boolean_t first; + int displ; + int prefix; + int imm; + int imm2; + int len; + struct i_addr address; + + get_value_inc(inst, loc, 1, FALSE); + short_addr = FALSE; + size = LONG; + seg = 0; + + /* + * Get prefixes + */ + prefix = TRUE; + do { + switch (inst) { + case 0x66: /* data16 */ + size = WORD; + break; + case 0x67: + short_addr = TRUE; + break; + case 0x26: + seg = "%es"; + break; + case 0x36: + seg = "%ss"; + break; + case 0x2e: + seg = "%cs"; + break; + case 0x3e: + seg = "%ds"; + break; + case 0x64: + seg = "%fs"; + break; + case 0x65: + seg = "%gs"; + break; + case 0xf0: + db_printf("lock "); + break; + case 0xf2: + db_printf("repne "); + break; + case 0xf3: + db_printf("repe "); /* XXX repe VS rep */ + break; + default: + prefix = FALSE; + break; + } + if (prefix) { + get_value_inc(inst, loc, 1, FALSE); + } + } while (prefix); + + if (inst >= 0xd8 && inst <= 0xdf) { + loc = db_disasm_esc(loc, inst, short_addr, size, seg); + db_printf("\n"); + return (loc); + } + + if (inst == 0x0f) { + get_value_inc(inst, loc, 1, FALSE); + ip = db_inst_0f[inst>>4]; + if (ip == 0) { + ip = &db_bad_inst; + } + else { + ip = &ip[inst&0xf]; + } + } + else + ip = &db_inst_table[inst]; + + if (ip->i_has_modrm) { + get_value_inc(regmodrm, loc, 1, FALSE); + loc = db_read_address(loc, short_addr, regmodrm, &address); + } + + i_name = ip->i_name; + i_size = ip->i_size; + i_mode = ip->i_mode; + + if (ip->i_extra == (char *)db_Grp1 || + ip->i_extra == (char *)db_Grp2 || + ip->i_extra == (char *)db_Grp6 || + ip->i_extra == (char *)db_Grp7 || + ip->i_extra == (char *)db_Grp8) { + i_name = ((char **)ip->i_extra)[f_reg(regmodrm)]; + } + else if (ip->i_extra == (char *)db_Grp3) { + ip = (struct inst *)ip->i_extra; + ip = &ip[f_reg(regmodrm)]; + i_name = ip->i_name; + i_mode = ip->i_mode; + } + else if (ip->i_extra == (char *)db_Grp4 || + ip->i_extra == (char *)db_Grp5) { + ip = (struct inst *)ip->i_extra; + ip = &ip[f_reg(regmodrm)]; + i_name = ip->i_name; + i_mode = ip->i_mode; + i_size = ip->i_size; + } + + if (i_size == SDEP) { + if (size == WORD) + db_printf(i_name); + else + db_printf(ip->i_extra); + } + else { + db_printf(i_name); + if (i_size != NONE) { + if (i_size == BYTE) { + db_printf("b"); + size = BYTE; + } + else if (i_size == WORD) { + db_printf("w"); + size = WORD; + } + else if (size == WORD) + db_printf("w"); + else + db_printf("l"); + } + } + db_printf("\t"); + for (first = TRUE; + i_mode != 0; + i_mode >>= 8, first = FALSE) + { + if (!first) + db_printf(","); + + switch (i_mode & 0xFF) { + + case E: + db_print_address(seg, size, &address); + break; + + case Eind: + db_printf("*"); + db_print_address(seg, size, &address); + break; + + case Ew: + db_print_address(seg, WORD, &address); + break; + + case Eb: + db_print_address(seg, BYTE, &address); + break; + + case R: + db_printf("%s", db_reg[size][f_reg(regmodrm)]); + break; + + case Rw: + db_printf("%s", db_reg[WORD][f_reg(regmodrm)]); + break; + + case Ri: + db_printf("%s", db_reg[size][f_rm(inst)]); + break; + + case S: + db_printf("%s", db_seg_reg[f_reg(regmodrm)]); + break; + + case Si: + db_printf("%s", db_seg_reg[f_reg(inst)]); + break; + + case A: + db_printf("%s", db_reg[size][0]); /* acc */ + break; + + case BX: + if (seg) + db_printf("%s:", seg); + db_printf("(%s)", short_addr ? "%bx" : "%ebx"); + break; + + case CL: + db_printf("%%cl"); + break; + + case DX: + db_printf("%%dx"); + break; + + case SI: + if (seg) + db_printf("%s:", seg); + db_printf("(%s)", short_addr ? "%si" : "%esi"); + break; + + case DI: + db_printf("%%es:(%s)", short_addr ? "%di" : "%edi"); + break; + + case CR: + db_printf("%%cr%d", f_reg(regmodrm)); + break; + + case DR: + db_printf("%%dr%d", f_reg(regmodrm)); + break; + + case TR: + db_printf("%%tr%d", f_reg(regmodrm)); + break; + + case I: + len = db_lengths[size]; + get_value_inc(imm, loc, len, FALSE);/* unsigned */ + db_printf("$%#n", imm); + break; + + case Is: + len = db_lengths[size]; + get_value_inc(imm, loc, len, TRUE); /* signed */ + db_printf("$%#r", imm); + break; + + case Ib: + get_value_inc(imm, loc, 1, FALSE); /* unsigned */ + db_printf("$%#n", imm); + break; + + case Ibs: + get_value_inc(imm, loc, 1, TRUE); /* signed */ + db_printf("$%#r", imm); + break; + + case Iw: + get_value_inc(imm, loc, 2, FALSE); /* unsigned */ + db_printf("$%#n", imm); + break; + + case Il: + get_value_inc(imm, loc, 4, FALSE); + db_printf("$%#n", imm); + break; + + case O: + if (short_addr) { + get_value_inc(displ, loc, 2, TRUE); + } + else { + get_value_inc(displ, loc, 4, TRUE); + } + if (seg) + db_printf("%s:%#r",seg, displ); + else + db_printsym((db_addr_t)displ, DB_STGY_ANY); + break; + + case Db: + get_value_inc(displ, loc, 1, TRUE); + db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN); + break; + + case Dl: + get_value_inc(displ, loc, 4, TRUE); + db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN); + break; + + case o1: + db_printf("$1"); + break; + + case o3: + db_printf("$3"); + break; + + case OS: + get_value_inc(imm, loc, 4, FALSE); /* offset */ + get_value_inc(imm2, loc, 2, FALSE); /* segment */ + db_printf("$%#n,%#n", imm2, imm); + break; + } + } + + if (altfmt == 0) { + if (inst == 0xe9 || inst == 0xeb) { + /* + * GAS pads to longword boundary after unconditional jumps. + */ + loc = (loc + (4-1)) & ~(4-1); + } + } + db_printf("\n"); + return (loc); +} + diff --git a/sys/i386/i386/db_interface.c b/sys/i386/i386/db_interface.c new file mode 100644 index 000000000000..31e7849e016d --- /dev/null +++ b/sys/i386/i386/db_interface.c @@ -0,0 +1,255 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_interface.c,v $ + * Revision 1.1 1992/03/25 21:42:03 pace + * Initial revision + * + * Revision 2.4 91/02/05 17:11:13 mrt + * Changed to new Mach copyright + * [91/02/01 17:31:17 mrt] + * + * Revision 2.3 90/12/04 14:45:55 jsb + * Changes for merged intel/pmap.{c,h}. + * [90/12/04 11:14:41 jsb] + * + * Revision 2.2 90/10/25 14:44:43 rwd + * Added watchpoint support. + * [90/10/18 rpd] + * + * Created. + * [90/07/25 dbg] + * + * + */ + +/* + * Interface to new debugger. + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> + +#include <sys/reboot.h> +#include <vm/vm_statistics.h> +#include <vm/pmap.h> + +#include <setjmp.h> +#include <sys/systm.h> /* just for boothowto --eichin */ +int db_active = 0; + +/* + * Received keyboard interrupt sequence. + */ +kdb_kbd_trap(regs) + struct i386_saved_state *regs; +{ + if (db_active == 0 && (boothowto & RB_KDB)) { + printf("\n\nkernel: keyboard interrupt\n"); + kdb_trap(-1, 0, regs); + } +} + +/* + * kdb_trap - field a TRACE or BPT trap + */ + +static jmp_buf *db_nofault = 0; + +kdb_trap(type, code, regs) + int type, code; + register struct i386_saved_state *regs; +{ +#if 0 + if ((boothowto&RB_KDB) == 0) + return(0); +#endif + + switch (type) { + case T_BPTFLT /* T_INT3 */: /* breakpoint */ + case T_KDBTRAP /* T_WATCHPOINT */: /* watchpoint */ + case T_PRIVINFLT /* T_DEBUG */: /* single_step */ + + case -1: /* keyboard interrupt */ + break; + + default: + kdbprinttrap(type, code); + + if (db_nofault) { + jmp_buf *no_fault = db_nofault; + db_nofault = 0; + longjmp(*no_fault, 1); + } + } + + /* Should switch to kdb`s own stack here. */ + + ddb_regs = *regs; + + if ((regs->tf_cs & 0x3) == 0) { + /* + * Kernel mode - esp and ss not saved + */ + ddb_regs.tf_esp = (int)®s->tf_esp; /* kernel stack pointer */ +#if 0 + ddb_regs.ss = KERNEL_DS; +#endif + asm(" movw %%ss,%%ax; movl %%eax,%0 " + : "=g" (ddb_regs.tf_ss) + : + : "ax"); + } + + db_active++; + cnpollc(TRUE); + db_trap(type, code); + cnpollc(FALSE); + db_active--; + + regs->tf_eip = ddb_regs.tf_eip; + regs->tf_eflags = ddb_regs.tf_eflags; + regs->tf_eax = ddb_regs.tf_eax; + regs->tf_ecx = ddb_regs.tf_ecx; + regs->tf_edx = ddb_regs.tf_edx; + regs->tf_ebx = ddb_regs.tf_ebx; + if (regs->tf_cs & 0x3) { + /* + * user mode - saved esp and ss valid + */ + regs->tf_esp = ddb_regs.tf_esp; /* user stack pointer */ + regs->tf_ss = ddb_regs.tf_ss & 0xffff; /* user stack segment */ + } + regs->tf_ebp = ddb_regs.tf_ebp; + regs->tf_esi = ddb_regs.tf_esi; + regs->tf_edi = ddb_regs.tf_edi; + regs->tf_es = ddb_regs.tf_es & 0xffff; + regs->tf_cs = ddb_regs.tf_cs & 0xffff; + regs->tf_ds = ddb_regs.tf_ds & 0xffff; +#if 0 + regs->tf_fs = ddb_regs.tf_fs & 0xffff; + regs->tf_gs = ddb_regs.tf_gs & 0xffff; +#endif + + return (1); +} + +/* + * Print trap reason. + */ +kdbprinttrap(type, code) + int type, code; +{ + printf("kernel: "); + printf("type %d", type); + printf(" trap, code=%x\n", code); +} + +/* + * Read bytes from kernel address space for debugger. + */ + +extern jmp_buf db_jmpbuf; + +void +db_read_bytes(addr, size, data) + vm_offset_t addr; + register int size; + register char *data; +{ + register char *src; + + db_nofault = &db_jmpbuf; + + src = (char *)addr; + while (--size >= 0) + *data++ = *src++; + + db_nofault = 0; +} + +struct pte *pmap_pte(pmap_t, vm_offset_t); + +/* + * Write bytes to kernel address space for debugger. + */ +void +db_write_bytes(addr, size, data) + vm_offset_t addr; + register int size; + register char *data; +{ + register char *dst; + + register pt_entry_t *ptep0 = 0; + pt_entry_t oldmap0 = { 0 }; + vm_offset_t addr1; + register pt_entry_t *ptep1 = 0; + pt_entry_t oldmap1 = { 0 }; + extern char etext; + + db_nofault = &db_jmpbuf; + + if (addr >= VM_MIN_KERNEL_ADDRESS && + addr <= (vm_offset_t)&etext) + { + ptep0 = pmap_pte(kernel_pmap, addr); + oldmap0 = *ptep0; + *(int *)ptep0 |= /* INTEL_PTE_WRITE */ PG_RW; + + addr1 = i386_trunc_page(addr + size - 1); + if (i386_trunc_page(addr) != addr1) { + /* data crosses a page boundary */ + + ptep1 = pmap_pte(kernel_pmap, addr1); + oldmap1 = *ptep1; + *(int *)ptep1 |= /* INTEL_PTE_WRITE */ PG_RW; + } + tlbflush(); + } + + dst = (char *)addr; + + while (--size >= 0) + *dst++ = *data++; + + db_nofault = 0; + + if (ptep0) { + *ptep0 = oldmap0; + if (ptep1) { + *ptep1 = oldmap1; + } + tlbflush(); + } +} + +Debugger (msg) +char *msg; +{ + asm ("int $3"); +} diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c new file mode 100644 index 000000000000..cbffbbc06786 --- /dev/null +++ b/sys/i386/i386/db_trace.c @@ -0,0 +1,292 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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: db_trace.c,v $ + * Revision 1.1 1992/03/25 21:42:05 pace + * Initial revision + * + * Revision 2.6 91/02/05 17:11:21 mrt + * Changed to new Mach copyright + * [91/02/01 17:31:32 mrt] + * + * Revision 2.5 91/01/09 19:55:27 rpd + * Fixed stack tracing for threads without kernel stacks. + * [91/01/09 rpd] + * + * Revision 2.4 91/01/08 15:10:22 rpd + * Reorganized the pcb. + * [90/12/11 rpd] + * + * Revision 2.3 90/11/05 14:27:07 rpd + * If we can not guess the number of args to a function, use 5 vs 0. + * [90/11/02 rvb] + * + * Revision 2.2 90/08/27 21:56:20 dbg + * Import db_sym.h. + * [90/08/21 dbg] + * Fix includes. + * [90/08/08 dbg] + * Created from rvb's code for new debugger. + * [90/07/11 dbg] + * + */ +#include "param.h" +#include "proc.h" +#include <machine/db_machdep.h> + +#include <ddb/db_access.h> +#include <ddb/db_sym.h> +#include <ddb/db_variables.h> + +/* + * Machine register set. + */ +struct db_variable db_regs[] = { + "cs", (int *)&ddb_regs.tf_cs, FCN_NULL, + "ds", (int *)&ddb_regs.tf_ds, FCN_NULL, + "es", (int *)&ddb_regs.tf_es, FCN_NULL, +#if 0 + "fs", (int *)&ddb_regs.tf_fs, FCN_NULL, + "gs", (int *)&ddb_regs.tf_gs, FCN_NULL, +#endif + "ss", (int *)&ddb_regs.tf_ss, FCN_NULL, + "eax", (int *)&ddb_regs.tf_eax, FCN_NULL, + "ecx", (int *)&ddb_regs.tf_ecx, FCN_NULL, + "edx", (int *)&ddb_regs.tf_edx, FCN_NULL, + "ebx", (int *)&ddb_regs.tf_ebx, FCN_NULL, + "esp", (int *)&ddb_regs.tf_esp,FCN_NULL, + "ebp", (int *)&ddb_regs.tf_ebp, FCN_NULL, + "esi", (int *)&ddb_regs.tf_esi, FCN_NULL, + "edi", (int *)&ddb_regs.tf_edi, FCN_NULL, + "eip", (int *)&ddb_regs.tf_eip, FCN_NULL, + "efl", (int *)&ddb_regs.tf_eflags, FCN_NULL, +}; +struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); + +/* + * Stack trace. + */ +#define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS) + +struct i386_frame { + struct i386_frame *f_frame; + int f_retaddr; + int f_arg0; +}; + +#define TRAP 1 +#define INTERRUPT 2 + +db_addr_t db_trap_symbol_value = 0; +db_addr_t db_kdintr_symbol_value = 0; +boolean_t db_trace_symbols_found = FALSE; + +void +db_find_trace_symbols() +{ + db_expr_t value; + if (db_value_of_name("_trap", &value)) + db_trap_symbol_value = (db_addr_t) value; + if (db_value_of_name("_kdintr", &value)) + db_kdintr_symbol_value = (db_addr_t) value; + db_trace_symbols_found = TRUE; +} + +/* + * Figure out how many arguments were passed into the frame at "fp". + */ +int +db_numargs(fp) + struct i386_frame *fp; +{ + int *argp; + int inst; + int args; + extern char etext[]; + + argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE); + if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext) + args = 5; + else { + inst = db_get_value((int)argp, 4, FALSE); + if ((inst & 0xff) == 0x59) /* popl %ecx */ + args = 1; + else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */ + args = ((inst >> 16) & 0xff) / 4; + else + args = 5; + } + return (args); +} + +/* + * Figure out the next frame up in the call stack. + * For trap(), we print the address of the faulting instruction and + * proceed with the calling frame. We return the ip that faulted. + * If the trap was caused by jumping through a bogus pointer, then + * the next line in the backtrace will list some random function as + * being called. It should get the argument list correct, though. + * It might be possible to dig out from the next frame up the name + * of the function that faulted, but that could get hairy. + */ +void +db_nextframe(fp, ip, argp, is_trap) + struct i386_frame **fp; /* in/out */ + db_addr_t *ip; /* out */ + int *argp; /* in */ + int is_trap; /* in */ +{ + struct i386_saved_state *saved_regs; + + if (is_trap == 0) { + *ip = (db_addr_t) + db_get_value((int) &(*fp)->f_retaddr, 4, FALSE); + *fp = (struct i386_frame *) + db_get_value((int) &(*fp)->f_frame, 4, FALSE); + } else { + /* + * We know that trap() has 1 argument and we know that + * it is an (int *). + */ + saved_regs = (struct i386_saved_state *) + db_get_value((int)argp, 4, FALSE); + db_printf("--- trap (number %d) ---\n", + saved_regs->tf_trapno & 0xffff); + db_printsym(saved_regs->tf_eip, DB_STGY_XTRN); + db_printf(":\n"); + *fp = (struct i386_frame *)saved_regs->tf_ebp; + *ip = (db_addr_t)saved_regs->tf_eip; + } + +} + +void +db_stack_trace_cmd(addr, have_addr, count, modif) + db_expr_t addr; + boolean_t have_addr; + db_expr_t count; + char *modif; +{ + struct i386_frame *frame, *lastframe; + int *argp; + db_addr_t callpc; + int is_trap; + boolean_t kernel_only = TRUE; + boolean_t trace_thread = FALSE; + + if (!db_trace_symbols_found) + db_find_trace_symbols(); + + { + register char *cp = modif; + register char c; + + while ((c = *cp++) != 0) { + if (c == 't') + trace_thread = TRUE; + if (c == 'u') + kernel_only = FALSE; + } + } + + if (count == -1) + count = 65535; + + if (!have_addr) { + frame = (struct i386_frame *)ddb_regs.tf_ebp; + callpc = (db_addr_t)ddb_regs.tf_eip; + } + else if (trace_thread) { + printf ("db_trace.c: can't trace thread\n"); + } + else { + frame = (struct i386_frame *)addr; + callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE); + } + + lastframe = 0; + while (count-- && frame != 0) { + register int narg; + char * name; + db_expr_t offset; + + if (INKERNEL((int)frame) && callpc == db_trap_symbol_value) { + narg = 1; + is_trap = TRAP; + } + else + if (INKERNEL((int)frame) && callpc == db_kdintr_symbol_value) { + is_trap = INTERRUPT; + narg = 0; + } + else { + is_trap = 0; + narg = db_numargs(frame); + } + + db_find_sym_and_offset(callpc, &name, &offset); + db_printf("%s(", name); + + argp = &frame->f_arg0; + while (narg) { + db_printf("%x", db_get_value((int)argp, 4, FALSE)); + argp++; + if (--narg != 0) + db_printf(","); + } + db_printf(") at "); + db_printsym(callpc, DB_STGY_XTRN); + db_printf("\n"); + + lastframe = frame; + db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap); + + if (frame == 0) { + /* end of chain */ + break; + } + if (INKERNEL((int)frame)) { + /* staying in kernel */ + if (frame <= lastframe) { + db_printf("Bad frame pointer: 0x%x\n", frame); + break; + } + } + else if (INKERNEL((int)lastframe)) { + /* switch from user to kernel */ + if (kernel_only) + break; /* kernel stack only */ + } + else { + /* in user */ + if (frame <= lastframe) { + db_printf("Bad frame pointer: 0x%x\n", frame); + break; + } + } + } +} diff --git a/sys/i386/i386/dkbad.c b/sys/i386/i386/dkbad.c new file mode 100644 index 000000000000..6974af1be266 --- /dev/null +++ b/sys/i386/i386/dkbad.c @@ -0,0 +1,67 @@ +/*- + * 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. + * + * @(#)dkbad.c 5.4 (Berkeley) 1/19/91 + */ + + +#ifndef NOBADSECT +#include "sys/param.h" +#include "sys/buf.h" +#include "sys/dkbad.h" + +/* + * Search the bad sector table looking for + * the specified sector. Return index if found. + * Return -1 if not found. + */ + +isbad(bt, cyl, trk, sec) + register struct dkbad *bt; +{ + register int i; + register long blk, bblk; + + blk = ((long)cyl << 16) + (trk << 8) + sec; + for (i = 0; i < 126; i++) { + bblk = ((long)bt->bt_bad[i].bt_cyl << 16) + bt->bt_bad[i].bt_trksec; + if (blk == bblk) + return (i); + if (blk < bblk || bblk < 0) + break; + } + return (-1); +} +#endif diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c new file mode 100644 index 000000000000..18ec37b289b7 --- /dev/null +++ b/sys/i386/i386/genassym.c @@ -0,0 +1,174 @@ +/*- + * Copyright (c) 1982, 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. + * + * @(#)genassym.c 5.11 (Berkeley) 5/10/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 24 Apr 93 Bruce Evans/Dave Rivers Npx-0.5 support + * + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/genassym.c,v 1.2 92/01/21 14:22:02 william Exp $"; + +#ifndef lint +static char sccsid[] = "@(#)genassym.c 5.11 (Berkeley) 5/10/91"; +#endif /* not lint */ + +#include "sys/param.h" +#include "sys/buf.h" +#include "sys/vmmeter.h" +#include "sys/proc.h" +#include "sys/user.h" +#include "sys/mbuf.h" +#include "sys/msgbuf.h" +#include "sys/resourcevar.h" +#include "machine/cpu.h" +#include "machine/trap.h" +#include "machine/psl.h" +#include "machine/reg.h" +#include "sys/syscall.h" +#include "vm/vm_param.h" +#include "vm/vm_map.h" +#include "machine/pmap.h" + +main() +{ + struct proc *p = (struct proc *)0; + struct vmmeter *vm = (struct vmmeter *)0; + struct user *up = (struct user *)0; + struct rusage *rup = (struct rusage *)0; + struct uprof *uprof = (struct uprof *)0; + struct vmspace *vms = (struct vmspace *)0; + vm_map_t map = (vm_map_t)0; + pmap_t pmap = (pmap_t)0; + struct pcb *pcb = (struct pcb *)0; + register unsigned i; + + printf("#define\tI386_CR3PAT %d\n", I386_CR3PAT); + printf("#define\tUDOT_SZ %d\n", sizeof(struct user)); + printf("#define\tP_LINK %d\n", &p->p_link); + printf("#define\tP_RLINK %d\n", &p->p_rlink); + printf("#define\tP_VMSPACE %d\n", &p->p_vmspace); + printf("#define\tVM_PMAP %d\n", &vms->vm_pmap); + printf("#define\tP_ADDR %d\n", &p->p_addr); + printf("#define\tP_PRI %d\n", &p->p_pri); + printf("#define\tP_STAT %d\n", &p->p_stat); + printf("#define\tP_WCHAN %d\n", &p->p_wchan); + printf("#define\tP_FLAG %d\n", &p->p_flag); + printf("#define\tP_PID %d\n", &p->p_pid); + printf("#define\tSSLEEP %d\n", SSLEEP); + printf("#define\tSRUN %d\n", SRUN); + printf("#define\tV_SWTCH %d\n", &vm->v_swtch); + printf("#define\tV_TRAP %d\n", &vm->v_trap); + printf("#define\tV_SYSCALL %d\n", &vm->v_syscall); + printf("#define\tV_INTR %d\n", &vm->v_intr); + printf("#define\tV_SOFT %d\n", &vm->v_soft); + printf("#define\tV_PDMA %d\n", &vm->v_pdma); + printf("#define\tV_FAULTS %d\n", &vm->v_faults); + printf("#define\tV_PGREC %d\n", &vm->v_pgrec); + printf("#define\tV_FASTPGREC %d\n", &vm->v_fastpgrec); + printf("#define\tUPAGES %d\n", UPAGES); + printf("#define\tHIGHPAGES %d\n", HIGHPAGES); + printf("#define\tCLSIZE %d\n", CLSIZE); + printf("#define\tNBPG %d\n", NBPG); + printf("#define\tNPTEPG %d\n", NPTEPG); + printf("#define\tPGSHIFT %d\n", PGSHIFT); + printf("#define\tSYSPTSIZE %d\n", SYSPTSIZE); + printf("#define\tUSRPTSIZE %d\n", USRPTSIZE); + printf("#define\tUSRIOSIZE %d\n", USRIOSIZE); +#ifdef SYSVSHM + printf("#define\tSHMMAXPGS %d\n", SHMMAXPGS); +#endif + printf("#define\tUSRSTACK %d\n", USRSTACK); + printf("#define\tMSGBUFPTECNT %d\n", btoc(sizeof (struct msgbuf))); + printf("#define\tNMBCLUSTERS %d\n", NMBCLUSTERS); + printf("#define\tMCLBYTES %d\n", MCLBYTES); + printf("#define\tPCB_LINK %d\n", &pcb->pcb_tss.tss_link); + printf("#define\tPCB_ESP0 %d\n", &pcb->pcb_tss.tss_esp0); + printf("#define\tPCB_SS0 %d\n", &pcb->pcb_tss.tss_ss0); + printf("#define\tPCB_ESP1 %d\n", &pcb->pcb_tss.tss_esp1); + printf("#define\tPCB_SS1 %d\n", &pcb->pcb_tss.tss_ss1); + printf("#define\tPCB_ESP2 %d\n", &pcb->pcb_tss.tss_esp2); + printf("#define\tPCB_SS2 %d\n", &pcb->pcb_tss.tss_ss2); + printf("#define\tPCB_CR3 %d\n", &pcb->pcb_tss.tss_cr3); + printf("#define\tPCB_EIP %d\n", &pcb->pcb_tss.tss_eip); + printf("#define\tPCB_EFLAGS %d\n", &pcb->pcb_tss.tss_eflags); + printf("#define\tPCB_EAX %d\n", &pcb->pcb_tss.tss_eax); + printf("#define\tPCB_ECX %d\n", &pcb->pcb_tss.tss_ecx); + printf("#define\tPCB_EDX %d\n", &pcb->pcb_tss.tss_edx); + printf("#define\tPCB_EBX %d\n", &pcb->pcb_tss.tss_ebx); + printf("#define\tPCB_ESP %d\n", &pcb->pcb_tss.tss_esp); + printf("#define\tPCB_EBP %d\n", &pcb->pcb_tss.tss_ebp); + printf("#define\tPCB_ESI %d\n", &pcb->pcb_tss.tss_esi); + printf("#define\tPCB_EDI %d\n", &pcb->pcb_tss.tss_edi); + printf("#define\tPCB_ES %d\n", &pcb->pcb_tss.tss_es); + printf("#define\tPCB_CS %d\n", &pcb->pcb_tss.tss_cs); + printf("#define\tPCB_SS %d\n", &pcb->pcb_tss.tss_ss); + printf("#define\tPCB_DS %d\n", &pcb->pcb_tss.tss_ds); + printf("#define\tPCB_FS %d\n", &pcb->pcb_tss.tss_fs); + printf("#define\tPCB_GS %d\n", &pcb->pcb_tss.tss_gs); + printf("#define\tPCB_LDT %d\n", &pcb->pcb_tss.tss_ldt); + printf("#define\tPCB_IOOPT %d\n", &pcb->pcb_tss.tss_ioopt); + printf("#define\tNKMEMCLUSTERS %d\n", NKMEMCLUSTERS); + printf("#define\tU_PROF %d\n", &up->u_stats.p_prof); + printf("#define\tU_PROFSCALE %d\n", &up->u_stats.p_prof.pr_scale); + printf("#define\tPR_BASE %d\n", &uprof->pr_base); + printf("#define\tPR_SIZE %d\n", &uprof->pr_size); + printf("#define\tPR_OFF %d\n", &uprof->pr_off); + printf("#define\tPR_SCALE %d\n", &uprof->pr_scale); + printf("#define\tRU_MINFLT %d\n", &rup->ru_minflt); + printf("#define\tPCB_FLAGS %d\n", &pcb->pcb_flags); + printf("#define\tPCB_SAVEFPU %d\n", &pcb->pcb_savefpu); +#ifdef notused + printf("#define\tFP_WASUSED %d\n", FP_WASUSED); + printf("#define\tFP_NEEDSSAVE %d\n", FP_NEEDSSAVE); + printf("#define\tFP_NEEDSRESTORE %d\n", FP_NEEDSRESTORE); +#endif + printf("#define\tFP_USESEMC %d\n", FP_USESEMC); + printf("#define\tPCB_SAVEEMC %d\n", &pcb->pcb_saveemc); + printf("#define\tPCB_CMAP2 %d\n", &pcb->pcb_cmap2); + printf("#define\tPCB_SIGC %d\n", pcb->pcb_sigc); + printf("#define\tPCB_IML %d\n", &pcb->pcb_iml); + printf("#define\tPCB_ONFAULT %d\n", &pcb->pcb_onfault); + + printf("#define\tB_READ %d\n", B_READ); + printf("#define\tENOENT %d\n", ENOENT); + printf("#define\tEFAULT %d\n", EFAULT); + printf("#define\tENAMETOOLONG %d\n", ENAMETOOLONG); + exit(0); +} diff --git a/sys/i386/i386/in_cksum.c b/sys/i386/i386/in_cksum.c new file mode 100644 index 000000000000..335dd358a7a9 --- /dev/null +++ b/sys/i386/i386/in_cksum.c @@ -0,0 +1,181 @@ +/*- + * Copyright (c) 1990 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 tahoe: in_cksum.c 1.2 86/01/05 + * @(#)in_cksum.c 1.3 (Berkeley) 1/19/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00104 + * -------------------- ----- ---------------------- + * + * 24 Jul 92 Bakul Shah Optimized some more + * + * 920724 i386 changes by Bakul Shah <bvs@bitblocks.com> + */ + +#include "param.h" +#include "sys/mbuf.h" + +/* + * Checksum routine for Internet Protocol family headers. + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * + * This implementation is 386 version. + */ + +#undef ADDCARRY +#define ADDCARRY(x) if ((x) > 0xffff) (x) -= 0xffff +#define REDUCE {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);} + +/* + * Thanks to gcc we don't have to guess + * which registers contain sum & w. + */ +#define CLC asm("clc") +#define ADD(n) asm("adcl " #n "(%2), %0": "=r"(sum): "0"(sum), "r"(w)) +#define MOP asm("adcl $0, %0": "=r"(sum): "0"(sum)) + +in_cksum(m, len) + register struct mbuf *m; + register int len; +{ + register u_short *w; + register unsigned sum = 0; + register int mlen = 0; + int byte_swapped = 0; + union { char c[2]; u_short s; } su; + + for (;m && len; m = m->m_next) { + if (m->m_len == 0) + continue; + w = mtod(m, u_short *); + if (mlen == -1) { + /* + * The first byte of this mbuf is the continuation + * of a word spanning between this mbuf and the + * last mbuf. + */ + + /* su.c[0] is already saved when scanning previous + * mbuf. sum was REDUCEd when we found mlen == -1 + */ + su.c[1] = *(u_char *)w; + sum += su.s; + w = (u_short *)((char *)w + 1); + mlen = m->m_len - 1; + len--; + } else + mlen = m->m_len; + if (len < mlen) + mlen = len; + len -= mlen; + /* + * Force to long boundary so we do longword aligned + * memory operations + */ + if (3 & (int) w) { + REDUCE; + if ((1 & (int) w) && (mlen > 0)) { + sum <<= 8; + su.c[0] = *(char *)w; + w = (u_short *)((char *)w + 1); + mlen--; + byte_swapped = 1; + } + if ((2 & (int) w) && (mlen >= 2)) { + sum += *w++; + mlen -= 2; + } + } + /* + * Do as much of the checksum as possible 32 bits at at time. + * In fact, this loop is unrolled to make overhead from + * branches &c small. + */ + while ((mlen -= 32) >= 0) { + /* + * Clear the carry flag, add with carry 16 words + * and fold-in last carry by adding a 0 with carry. + */ + CLC; + ADD(0); ADD(4); ADD(8); ADD(12); + ADD(16); ADD(20); ADD(24); ADD(28); + MOP; w += 16; + } + mlen += 32; + while ((mlen -= 8) >= 0) { + CLC; + ADD(0); ADD(4); + MOP; + w += 4; + } + mlen += 8; + if (mlen == 0 && byte_swapped == 0) + continue; /* worth 1% maybe ?? */ + REDUCE; + while ((mlen -= 2) >= 0) { + sum += *w++; + } + if (byte_swapped) { + sum <<= 8; + byte_swapped = 0; + if (mlen == -1) { + su.c[1] = *(char *)w; + sum += su.s; + mlen = 0; + } else + mlen = -1; + } else if (mlen == -1) + /* + * This mbuf has odd number of bytes. + * There could be a word split betwen + * this mbuf and the next mbuf. + * Save the last byte (to prepend to next mbuf). + */ + su.c[0] = *(char *)w; + } + + if (len) + printf("cksum: out of data\n"); + if (mlen == -1) { + /* The last mbuf has odd # of bytes. Follow the + standard (the odd byte is shifted left by 8 bits) */ + su.c[1] = 0; + sum += su.s; + } + REDUCE; + return (~sum & 0xffff); +} + diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s new file mode 100644 index 000000000000..d558dba24a58 --- /dev/null +++ b/sys/i386/i386/locore.s @@ -0,0 +1,1830 @@ +/*- + * 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. + * + * @(#)locore.s 7.3 (Berkeley) 5/13/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 5 00158 + * -------------------- ----- ---------------------- + * + * 06 Aug 92 Pace Willisson Allow VGA memory to be mapped + * 28 Nov 92 Frank MacLachlan Aligned addresses and data + * on 32bit boundaries. + * 25 Mar 93 Kevin Lahey Add syscall counter for vmstat + * 20 Apr 93 Bruce Evans New npx-0.5 code + * 25 Apr 93 Bruce Evans Support new interrupt code (intr-0.1) + */ + + +/* + * locore.s: 4BSD machine support for the Intel 386 + * Preliminary version + * Written by William F. Jolitz, 386BSD Project + */ + +#include "assym.s" +#include "machine/psl.h" +#include "machine/pte.h" + +#include "errno.h" + +#include "machine/trap.h" + +#include "machine/specialreg.h" +#include "i386/isa/debug.h" + +#define KDSEL 0x10 +#define SEL_RPL_MASK 0x0003 +#define TRAPF_CS_OFF (13 * 4) + +/* + * Note: This version greatly munged to avoid various assembler errors + * that may be fixed in newer versions of gas. Perhaps newer versions + * will have more pleasant appearance. + */ + + .set IDXSHIFT,10 + .set SYSTEM,0xFE000000 # virtual address of system start + /*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */ + .set SYSPDROFF,0x3F8 # Page dir index of System Base + +#define ALIGN_DATA .align 2 +#define ALIGN_TEXT .align 2,0x90 /* 4-byte boundaries, NOP-filled */ +#define SUPERALIGN_TEXT .align 4,0x90 /* 16-byte boundaries better for 486 */ + +/* NB: NOP now preserves registers so NOPs can be inserted anywhere */ +/* XXX: NOP and FASTER_NOP are misleadingly named */ +#ifdef BROKEN_HARDWARE_AND_OR_SOFTWARE /* XXX - rarely necessary */ +#define FASTER_NOP pushl %eax ; inb $0x84,%al ; popl %eax +#define NOP pushl %eax ; inb $0x84,%al ; inb $0x84,%al ; popl %eax +#else +#define FASTER_NOP +#define NOP +#endif + +/* + * PTmap is recursive pagemap at top of virtual address space. + * Within PTmap, the page directory can be found (third indirection). + */ + .set PDRPDROFF,0x3F7 # Page dir index of Page dir + .globl _PTmap, _PTD, _PTDpde, _Sysmap + .set _PTmap,0xFDC00000 + .set _PTD,0xFDFF7000 + .set _Sysmap,0xFDFF8000 + .set _PTDpde,0xFDFF7000+4*PDRPDROFF + +/* + * APTmap, APTD is the alternate recursive pagemap. + * It's used when modifying another process's page tables. + */ + .set APDRPDROFF,0x3FE # Page dir index of Page dir + .globl _APTmap, _APTD, _APTDpde + .set _APTmap,0xFF800000 + .set _APTD,0xFFBFE000 + .set _APTDpde,0xFDFF7000+4*APDRPDROFF + +/* + * Access to each processes kernel stack is via a region of + * per-process address space (at the beginning), immediatly above + * the user process stack. + */ + .set _kstack, USRSTACK + .globl _kstack + .set PPDROFF,0x3F6 + .set PPTEOFF,0x400-UPAGES # 0x3FE + +#define ENTRY(name) \ + .globl _/**/name; ALIGN_TEXT; _/**/name: +#define ALTENTRY(name) ENTRY(name) + +/* + * Initialization + */ + .data + .globl _cpu,_cold,_boothowto,_bootdev,_cyloffset,_atdevbase,_atdevphys +_cpu: .long 0 # are we 386, 386sx, or 486 +_cold: .long 1 # cold till we are not +_atdevbase: .long 0 # location of start of iomem in virtual +_atdevphys: .long 0 # location of device mapping ptes (phys) + + .globl _IdlePTD, _KPTphys +_IdlePTD: .long 0 +_KPTphys: .long 0 + + .space 512 +tmpstk: + .text + .globl start +start: movw $0x1234,%ax + movw %ax,0x472 # warm boot + jmp 1f + .space 0x500 # skip over warm boot shit + + /* + * pass parameters on stack (howto, bootdev, unit, cyloffset) + * note: (%esp) is return address of boot + * ( if we want to hold onto /boot, it's physical %esp up to _end) + */ + + 1: movl 4(%esp),%eax + movl %eax,_boothowto-SYSTEM + movl 8(%esp),%eax + movl %eax,_bootdev-SYSTEM + movl 12(%esp),%eax + movl %eax, _cyloffset-SYSTEM + + /* + * Finished with old stack; load new %esp now instead of later so + * we can trace this code without having to worry about the trace + * trap clobbering the memory test or the zeroing of the bss+bootstrap + * page tables. + * + * XXX - wdboot clears the bss after testing that this is safe. + * This is too wasteful - memory below 640K is scarce. The boot + * program should check: + * text+data <= &stack_variable - more_space_for_stack + * text+data+bss+pad+space_for_page_tables <= end_of_memory + * Oops, the gdt is in the carcass of the boot program so clearing + * the rest of memory is still not possible. + */ + movl $ tmpstk-SYSTEM,%esp # bootstrap stack end location + +#ifdef garbage + /* count up memory */ + + xorl %eax,%eax # start with base memory at 0x0 + #movl $ 0xA0000/NBPG,%ecx # look every 4K up to 640K + movl $ 0xA0,%ecx # look every 4K up to 640K +1: movl (%eax),%ebx # save location to check + movl $0xa55a5aa5,(%eax) # write test pattern + /* flush stupid cache here! (with bcopy (0,0,512*1024) ) */ + cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover + jne 2f + movl %ebx,(%eax) # restore memory + addl $ NBPG,%eax + loop 1b +2: shrl $12,%eax + movl %eax,_Maxmem-SYSTEM + + movl $0x100000,%eax # next, talley remaining memory + #movl $((0xFFF000-0x100000)/NBPG),%ecx + movl $(0xFFF-0x100),%ecx +1: movl (%eax),%ebx # save location to check + movl $0xa55a5aa5,(%eax) # write test pattern + cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover + jne 2f + movl %ebx,(%eax) # restore memory + addl $ NBPG,%eax + loop 1b +2: shrl $12,%eax + movl %eax,_Maxmem-SYSTEM +#endif + +/* find end of kernel image */ + movl $_end-SYSTEM,%ecx + addl $ NBPG-1,%ecx + andl $~(NBPG-1),%ecx + movl %ecx,%esi + +/* clear bss and memory for bootstrap pagetables. */ + movl $_edata-SYSTEM,%edi + subl %edi,%ecx + addl $(UPAGES+5)*NBPG,%ecx +/* + * Virtual address space of kernel: + * + * text | data | bss | page dir | proc0 kernel stack | usr stk map | Sysmap + * 0 1 2 3 4 + */ + xorl %eax,%eax # pattern + cld + rep + stosb + + movl %esi,_IdlePTD-SYSTEM /*physical address of Idle Address space */ + +#define fillkpt \ +1: movl %eax,(%ebx) ; \ + addl $ NBPG,%eax ; /* increment physical address */ \ + addl $4,%ebx ; /* next pte */ \ + loop 1b ; + +/* + * Map Kernel + * N.B. don't bother with making kernel text RO, as 386 + * ignores R/W AND U/S bits on kernel access (only v works) ! + * + * First step - build page tables + */ + movl %esi,%ecx # this much memory, + shrl $ PGSHIFT,%ecx # for this many pte s + addl $ UPAGES+4,%ecx # including our early context + movl $0xa0,%ecx # XXX - cover debugger pages + movl $PG_V|PG_KW,%eax # having these bits set, + lea (4*NBPG)(%esi),%ebx # physical address of KPT in proc 0, + movl %ebx,_KPTphys-SYSTEM # in the kernel page table, + fillkpt + +/* map I/O memory map */ + + movl $0x100-0xa0,%ecx # for this many pte s, + movl $(0xa0000|PG_V|PG_UW),%eax # having these bits set,(perhaps URW?) XXX 06 Aug 92 + movl %ebx,_atdevphys-SYSTEM # remember phys addr of ptes + fillkpt + + /* map proc 0's kernel stack into user page table page */ + + movl $ UPAGES,%ecx # for this many pte s, + lea (1*NBPG)(%esi),%eax # physical address in proc 0 + lea (SYSTEM)(%eax),%edx + movl %edx,_proc0paddr-SYSTEM # remember VA for 0th process init + orl $PG_V|PG_KW,%eax # having these bits set, + lea (3*NBPG)(%esi),%ebx # physical address of stack pt in proc 0 + addl $(PPTEOFF*4),%ebx + fillkpt + +/* + * Construct a page table directory + * (of page directory elements - pde's) + */ + /* install a pde for temporary double map of bottom of VA */ + lea (4*NBPG)(%esi),%eax # physical address of kernel page table + orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92 + movl %eax,(%esi) # which is where temp maps! + + /* kernel pde's */ + movl $ 3,%ecx # for this many pde s, + lea (SYSPDROFF*4)(%esi), %ebx # offset of pde for kernel + fillkpt + + /* install a pde recursively mapping page directory as a page table! */ + movl %esi,%eax # phys address of ptd in proc 0 + orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92 + movl %eax, PDRPDROFF*4(%esi) # which is where PTmap maps! + + /* install a pde to map kernel stack for proc 0 */ + lea (3*NBPG)(%esi),%eax # physical address of pt in proc 0 + orl $PG_V|PG_KW,%eax # pde entry is valid + movl %eax,PPDROFF*4(%esi) # which is where kernel stack maps! + + /* copy and convert stuff from old gdt and idt for debugger */ + + cmpl $0x0375c339,0x96104 # XXX - debugger signature + jne 1f + movb $1,_bdb_exists-SYSTEM +1: + pushal + subl $2*6,%esp + + sgdt (%esp) + movl 2(%esp),%esi # base address of current gdt + movl $_gdt-SYSTEM,%edi + movl %edi,2(%esp) + movl $8*18/4,%ecx + rep # copy gdt + movsl + movl $_gdt-SYSTEM,-8+2(%edi) # adjust gdt self-ptr + movb $0x92,-8+5(%edi) + + sidt 6(%esp) + movl 6+2(%esp),%esi # base address of current idt + movl 8+4(%esi),%eax # convert dbg descriptor to ... + movw 8(%esi),%ax + movl %eax,bdb_dbg_ljmp+1-SYSTEM # ... immediate offset ... + movl 8+2(%esi),%eax + movw %ax,bdb_dbg_ljmp+5-SYSTEM # ... and selector for ljmp + movl 24+4(%esi),%eax # same for bpt descriptor + movw 24(%esi),%ax + movl %eax,bdb_bpt_ljmp+1-SYSTEM + movl 24+2(%esi),%eax + movw %ax,bdb_bpt_ljmp+5-SYSTEM + + movl $_idt-SYSTEM,%edi + movl %edi,6+2(%esp) + movl $8*4/4,%ecx + rep # copy idt + movsl + + lgdt (%esp) + lidt 6(%esp) + + addl $2*6,%esp + popal + + /* load base of page directory, and enable mapping */ + movl %esi,%eax # phys address of ptd in proc 0 + orl $ I386_CR3PAT,%eax + movl %eax,%cr3 # load ptd addr into mmu + movl %cr0,%eax # get control word +#ifdef USE_486_WRITE_PROTECT + orl $CR0_PE|CR0_PG|CR0_WP,%eax # and let s page! +#else + orl $CR0_PE|CR0_PG,%eax # and let s page! +#endif + movl %eax,%cr0 # NOW! + + pushl $begin # jump to high mem! + ret + +begin: /* now running relocated at SYSTEM where the system is linked to run */ + + .globl _Crtat + movl _Crtat,%eax + subl $0xfe0a0000,%eax + movl _atdevphys,%edx # get pte PA + subl _KPTphys,%edx # remove base of ptes, now have phys offset + shll $ PGSHIFT-2,%edx # corresponding to virt offset + addl $ SYSTEM,%edx # add virtual base + movl %edx, _atdevbase + addl %eax,%edx + movl %edx,_Crtat + + /* set up bootstrap stack */ + movl $ _kstack+UPAGES*NBPG-4*12,%esp # bootstrap stack end location + xorl %eax,%eax # mark end of frames + movl %eax,%ebp + movl _proc0paddr, %eax + movl %esi, PCB_CR3(%eax) + + lea 7*NBPG(%esi),%esi # skip past stack. + pushl %esi + + /* relocate debugger gdt entries */ + + movl $_gdt+8*9,%eax # adjust slots 9-17 + movl $9,%ecx +reloc_gdt: + movb $0xfe,7(%eax) # top byte of base addresses, was 0, + addl $8,%eax # now SYSTEM>>24 + loop reloc_gdt + + cmpl $0,_bdb_exists + je 1f + int $3 +1: + + call _init386 # wire 386 chip for unix operation + + movl $0,_PTD + call _main + popl %esi + + .globl __ucodesel,__udatasel + movl __ucodesel,%eax + movl __udatasel,%ecx + # build outer stack frame + pushl %ecx # user ss + pushl $ USRSTACK # user esp + pushl %eax # user cs + pushl $0 # user ip + movl %cx,%ds + movl %cx,%es + movl %ax,%fs # double map cs to fs + movl %cx,%gs # and ds to gs + lret # goto user! + + pushl $lretmsg1 /* "should never get here!" */ + call _panic +lretmsg1: + .asciz "lret: toinit\n" + + + .set exec,59 + .set exit,1 + +#define LCALL(x,y) .byte 0x9a ; .long y; .word x +/* + * Icode is copied out to process 1 to exec /etc/init. + * If the exec fails, process 1 exits. + */ +ENTRY(icode) + # pushl $argv-_icode # gas fucks up again + movl $argv,%eax + subl $_icode,%eax + pushl %eax + + # pushl $init-_icode + movl $init,%eax + subl $_icode,%eax + pushl %eax + pushl %eax # dummy out rta + + movl %esp,%ebp + movl $exec,%eax + LCALL(0x7,0x0) + pushl %eax + movl $exit,%eax + pushl %eax # dummy out rta + LCALL(0x7,0x0) + +init: + .asciz "/sbin/init" + ALIGN_DATA +argv: + .long init+6-_icode # argv[0] = "init" ("/sbin/init" + 6) + .long eicode-_icode # argv[1] follows icode after copyout + .long 0 +eicode: + + .globl _szicode +_szicode: + .long _szicode-_icode + +ENTRY(sigcode) + call 12(%esp) + lea 28(%esp),%eax # scp (the call may have clobbered the + # copy at 8(%esp)) + # XXX - use genassym + pushl %eax + pushl %eax # junk to fake return address + movl $103,%eax # sigreturn() + LCALL(0x7,0) # enter kernel with args on stack + hlt # never gets here + + .globl _szsigcode +_szsigcode: + .long _szsigcode-_sigcode + + /* + * Support routines for GCC + */ +ENTRY(__udivsi3) + movl 4(%esp),%eax + xorl %edx,%edx + divl 8(%esp) + ret + +ENTRY(__divsi3) + movl 4(%esp),%eax + cltd + idivl 8(%esp) + ret + + /* + * I/O bus instructions via C + */ +ENTRY(inb) + movl 4(%esp),%edx + subl %eax,%eax # clr eax + NOP + inb %dx,%al + ret + + +ENTRY(inw) + movl 4(%esp),%edx + subl %eax,%eax # clr eax + NOP + inw %dx,%ax + ret + + +ENTRY(rtcin) + movl 4(%esp),%eax + outb %al,$0x70 + subl %eax,%eax # clr eax + inb $0x71,%al + ret + +ENTRY(outb) + movl 4(%esp),%edx + NOP + movl 8(%esp),%eax + outb %al,%dx + NOP + ret + +ENTRY(outw) + movl 4(%esp),%edx + NOP + movl 8(%esp),%eax + outw %ax,%dx + NOP + ret + + /* + * void bzero(void *base, u_int cnt) + */ + +ENTRY(bzero) + pushl %edi + movl 8(%esp),%edi + movl 12(%esp),%ecx + xorl %eax,%eax + shrl $2,%ecx + cld + rep + stosl + movl 12(%esp),%ecx + andl $3,%ecx + rep + stosb + popl %edi + ret + + /* + * fillw (pat,base,cnt) + */ + +ENTRY(fillw) + pushl %edi + movl 8(%esp),%eax + movl 12(%esp),%edi + movl 16(%esp),%ecx + cld + rep + stosw + popl %edi + ret + +ENTRY(bcopyb) + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + cmpl %esi,%edi /* potentially overlapping? */ + jnb 1f + cld /* nope, copy forwards */ + rep + movsb + popl %edi + popl %esi + ret + + ALIGN_TEXT +1: + addl %ecx,%edi /* copy backwards. */ + addl %ecx,%esi + std + decl %edi + decl %esi + rep + movsb + popl %edi + popl %esi + cld + ret + +ENTRY(bcopyw) + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + cmpl %esi,%edi /* potentially overlapping? */ + jnb 1f + cld /* nope, copy forwards */ + shrl $1,%ecx /* copy by 16-bit words */ + rep + movsw + adc %ecx,%ecx /* any bytes left? */ + rep + movsb + popl %edi + popl %esi + ret + + ALIGN_TEXT +1: + addl %ecx,%edi /* copy backwards */ + addl %ecx,%esi + std + andl $1,%ecx /* any fractional bytes? */ + decl %edi + decl %esi + rep + movsb + movl 20(%esp),%ecx /* copy remainder by 16-bit words */ + shrl $1,%ecx + decl %esi + decl %edi + rep + movsw + popl %edi + popl %esi + cld + ret + +ENTRY(bcopyx) + movl 16(%esp),%eax + cmpl $2,%eax + je _bcopyw + cmpl $4,%eax + jne _bcopyb + /* + * Fall through to bcopy. ENTRY() provides harmless fill bytes. + */ + + /* + * (ov)bcopy (src,dst,cnt) + * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800 + * Changed by bde to not bother returning %eax = 0. + */ + +ENTRY(ovbcopy) +ENTRY(bcopy) + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + cmpl %esi,%edi /* potentially overlapping? */ + jnb 1f + cld /* nope, copy forwards */ + shrl $2,%ecx /* copy by 32-bit words */ + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx /* any bytes left? */ + rep + movsb + popl %edi + popl %esi + ret + + ALIGN_TEXT +1: + addl %ecx,%edi /* copy backwards */ + addl %ecx,%esi + std + andl $3,%ecx /* any fractional bytes? */ + decl %edi + decl %esi + rep + movsb + movl 20(%esp),%ecx /* copy remainder by 32-bit words */ + shrl $2,%ecx + subl $3,%esi + subl $3,%edi + rep + movsl + popl %edi + popl %esi + cld + ret + +#ifdef notdef +ENTRY(copyout) + movl _curpcb, %eax + movl $cpyflt, PCB_ONFAULT(%eax) # in case we page/protection violate + pushl %esi + pushl %edi + pushl %ebx + movl 16(%esp), %esi + movl 20(%esp), %edi + movl 24(%esp), %ebx + + /* first, check to see if "write fault" */ +1: movl %edi, %eax +#ifdef notyet + shrl $IDXSHIFT, %eax /* fetch pte associated with address */ + andb $0xfc, %al + movl _PTmap(%eax), %eax + + andb $7, %al /* if we are the one case that won't trap... */ + cmpb $5, %al + jne 2f + /* ... then simulate the trap! */ + pushl %edi + call _trapwrite /* trapwrite(addr) */ + popl %edx + + cmpl $0, %eax /* if not ok, return */ + jne cpyflt + /* otherwise, continue with reference */ +2: + movl %edi, %eax /* calculate remainder this pass */ + andl $0xfffff000, %eax + movl $NBPG, %ecx + subl %eax, %ecx + cmpl %ecx, %ebx + jle 3f + movl %ebx, %ecx +3: subl %ecx, %ebx + movl %ecx, %edx +#else + movl %ebx, %ecx + movl %ebx, %edx +#endif + + shrl $2,%ecx /* movem */ + cld + rep + movsl + movl %edx, %ecx /* don't depend on ecx here! */ + andl $3, %ecx + rep + movsb + +#ifdef notyet + cmpl $0, %ebx + jl 1b +#endif + + popl %ebx + popl %edi + popl %esi + xorl %eax,%eax + movl _curpcb,%edx + movl %eax,PCB_ONFAULT(%edx) + ret + +ENTRY(copyin) + movl _curpcb,%eax + movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate + pushl %esi + pushl %edi + pushl %ebx # XXX - not used, but affects stack offsets + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + shrl $2,%ecx + cld + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx + rep + movsb + popl %ebx + popl %edi + popl %esi + xorl %eax,%eax + movl _curpcb,%edx + movl %eax,PCB_ONFAULT(%edx) + ret + + ALIGN_TEXT +cpyflt: + popl %ebx + popl %edi + popl %esi + movl _curpcb,%edx + movl $0,PCB_ONFAULT(%edx) + movl $ EFAULT,%eax + ret +#else +ENTRY(copyout) + movl _curpcb,%eax + movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + shrl $2,%ecx + cld + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx + rep + movsb + popl %edi + popl %esi + xorl %eax,%eax + movl _curpcb,%edx + movl %eax,PCB_ONFAULT(%edx) + ret + +ENTRY(copyin) + movl _curpcb,%eax + movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate + pushl %esi + pushl %edi + movl 12(%esp),%esi + movl 16(%esp),%edi + movl 20(%esp),%ecx + shrl $2,%ecx + cld + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx + rep + movsb + popl %edi + popl %esi + xorl %eax,%eax + movl _curpcb,%edx + movl %eax,PCB_ONFAULT(%edx) + ret + + ALIGN_TEXT +cpyflt: popl %edi + popl %esi + movl _curpcb,%edx + movl $0,PCB_ONFAULT(%edx) + movl $ EFAULT,%eax + ret + +#endif + + # insb(port,addr,cnt) +ENTRY(insb) + pushl %edi + movw 8(%esp),%dx + movl 12(%esp),%edi + movl 16(%esp),%ecx + cld + NOP + rep + insb + NOP + movl %edi,%eax + popl %edi + ret + + # insw(port,addr,cnt) +ENTRY(insw) + pushl %edi + movw 8(%esp),%dx + movl 12(%esp),%edi + movl 16(%esp),%ecx + cld + NOP + .byte 0x66,0xf2,0x6d # rep insw + NOP + movl %edi,%eax + popl %edi + ret + + # outsw(port,addr,cnt) +ENTRY(outsw) + pushl %esi + movw 8(%esp),%dx + movl 12(%esp),%esi + movl 16(%esp),%ecx + cld + NOP + .byte 0x66,0xf2,0x6f # rep outsw + NOP + movl %esi,%eax + popl %esi + ret + + # outsb(port,addr,cnt) +ENTRY(outsb) + pushl %esi + movw 8(%esp),%dx + movl 12(%esp),%esi + movl 16(%esp),%ecx + cld + NOP + rep + outsb + NOP + movl %esi,%eax + popl %esi + ret + + /* + * void lgdt(struct region_descriptor *rdp); + */ +ENTRY(lgdt) + /* reload the descriptor table */ + movl 4(%esp),%eax + lgdt (%eax) + /* flush the prefetch q */ + jmp 1f + nop +1: + /* reload "stale" selectors */ + movl $KDSEL,%eax + movl %ax,%ds + movl %ax,%es + movl %ax,%ss + + /* reload code selector by turning return into intersegmental return */ + movl (%esp),%eax + pushl %eax + # movl $KCSEL,4(%esp) + movl $8,4(%esp) + lret + + /* + * void lidt(struct region_descriptor *rdp); + */ +ENTRY(lidt) + movl 4(%esp),%eax + lidt (%eax) + ret + + /* + * void lldt(u_short sel) + */ +ENTRY(lldt) + lldt 4(%esp) + ret + + /* + * void ltr(u_short sel) + */ +ENTRY(ltr) + ltr 4(%esp) + ret + + /* + * void lcr3(caddr_t cr3) + */ + ALIGN_TEXT +ENTRY(load_cr3) +ALTENTRY(lcr3) + movl 4(%esp),%eax + orl $ I386_CR3PAT,%eax + movl %eax,%cr3 + ret + + # tlbflush() +ENTRY(tlbflush) + movl %cr3,%eax + orl $ I386_CR3PAT,%eax + movl %eax,%cr3 + ret + + # lcr0(cr0) +ENTRY(lcr0) +ALTENTRY(load_cr0) + movl 4(%esp),%eax + movl %eax,%cr0 + ret + + # rcr0() +ENTRY(rcr0) + movl %cr0,%eax + ret + + # rcr2() +ENTRY(rcr2) + movl %cr2,%eax + ret + + # rcr3() +ENTRY(_cr3) +ALTENTRY(rcr3) + movl %cr3,%eax + ret + + # ssdtosd(*ssdp,*sdp) +ENTRY(ssdtosd) + pushl %ebx + movl 8(%esp),%ecx + movl 8(%ecx),%ebx + shll $16,%ebx + movl (%ecx),%edx + roll $16,%edx + movb %dh,%bl + movb %dl,%bh + rorl $8,%ebx + movl 4(%ecx),%eax + movw %ax,%dx + andl $0xf0000,%eax + orl %eax,%ebx + movl 12(%esp),%ecx + movl %edx,(%ecx) + movl %ebx,4(%ecx) + popl %ebx + ret + +/* + * {fu,su},{byte,word} + */ +ALTENTRY(fuiword) +ENTRY(fuword) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) + movl 4(%esp),%edx + .byte 0x65 # use gs + movl (%edx),%eax + movl $0,PCB_ONFAULT(%ecx) + ret + +ENTRY(fusword) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + .byte 0x65 # use gs + movzwl (%edx),%eax + movl $0,PCB_ONFAULT(%ecx) + ret + +ALTENTRY(fuibyte) +ENTRY(fubyte) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + .byte 0x65 # use gs + movzbl (%edx),%eax + movl $0,PCB_ONFAULT(%ecx) + ret + + ALIGN_TEXT +fusufault: + movl _curpcb,%ecx + xorl %eax,%eax + movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate + decl %eax + ret + +ALTENTRY(suiword) +ENTRY(suword) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + movl 8(%esp),%eax + +#ifdef notdef + shrl $IDXSHIFT, %edx /* fetch pte associated with address */ + andb $0xfc, %dl + movl _PTmap(%edx), %edx + + andb $7, %dl /* if we are the one case that won't trap... */ + cmpb $5 , %edx + jne 1f + /* ... then simulate the trap! */ + pushl %edi + call _trapwrite /* trapwrite(addr) */ + popl %edx + cmpl $0, %eax /* if not ok, return */ + jne fusufault + movl 8(%esp),%eax /* otherwise, continue with reference */ +1: + movl 4(%esp),%edx +#endif + .byte 0x65 # use gs + movl %eax,(%edx) + xorl %eax,%eax + movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate + ret + +ENTRY(susword) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + movl 8(%esp),%eax +#ifdef notdef +shrl $IDXSHIFT, %edx /* calculate pte address */ +andb $0xfc, %dl +movl _PTmap(%edx), %edx +andb $7, %edx /* if we are the one case that won't trap... */ +cmpb $5 , %edx +jne 1f +/* ..., then simulate the trap! */ + pushl %edi + call _trapwrite /* trapwrite(addr) */ + popl %edx +movl _curpcb, %ecx # restore trashed registers +cmpl $0, %eax /* if not ok, return */ +jne fusufault +movl 8(%esp),%eax +1: movl 4(%esp),%edx +#endif + .byte 0x65 # use gs + movw %ax,(%edx) + xorl %eax,%eax + movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate + ret + +ALTENTRY(suibyte) +ENTRY(subyte) + movl _curpcb,%ecx + movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate + movl 4(%esp),%edx + movl 8(%esp),%eax +#ifdef notdef +shrl $IDXSHIFT, %edx /* calculate pte address */ +andb $0xfc, %dl +movl _PTmap(%edx), %edx +andb $7, %edx /* if we are the one case that won't trap... */ +cmpb $5 , %edx +jne 1f +/* ..., then simulate the trap! */ + pushl %edi + call _trapwrite /* trapwrite(addr) */ + popl %edx +movl _curpcb, %ecx # restore trashed registers +cmpl $0, %eax /* if not ok, return */ +jne fusufault +movl 8(%esp),%eax +1: movl 4(%esp),%edx +#endif + .byte 0x65 # use gs + movb %eax,(%edx) + xorl %eax,%eax + movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate + ret + +ENTRY(setjmp) + movl 4(%esp),%eax + movl %ebx, (%eax) # save ebx + movl %esp, 4(%eax) # save esp + movl %ebp, 8(%eax) # save ebp + movl %esi,12(%eax) # save esi + movl %edi,16(%eax) # save edi + movl (%esp),%edx # get rta + movl %edx,20(%eax) # save eip + xorl %eax,%eax # return (0); + ret + +ENTRY(longjmp) + movl 4(%esp),%eax + movl (%eax),%ebx # restore ebx + movl 4(%eax),%esp # restore esp + movl 8(%eax),%ebp # restore ebp + movl 12(%eax),%esi # restore esi + movl 16(%eax),%edi # restore edi + movl 20(%eax),%edx # get rta + movl %edx,(%esp) # put in return frame + xorl %eax,%eax # return (1); + incl %eax + ret +/* + * The following primitives manipulate the run queues. + * _whichqs tells which of the 32 queues _qs + * have processes in them. Setrq 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_pri, divided by 4 + * actually to shrink the 0-127 range of priorities into the 32 available + * queues. + */ + + .globl _whichqs,_qs,_cnt,_panic + .comm _noproc,4 + .comm _runrun,4 + +/* + * Setrq(p) + * + * Call should be made at spl6(), and p->p_stat should be SRUN + */ +ENTRY(setrq) + movl 4(%esp),%eax + cmpl $0,P_RLINK(%eax) # should not be on q already + je set1 + pushl $set2 + call _panic +set1: + movzbl P_PRI(%eax),%edx + shrl $2,%edx + btsl %edx,_whichqs # set q full bit + shll $3,%edx + addl $_qs,%edx # locate q hdr + movl %edx,P_LINK(%eax) # link process on tail of q + movl P_RLINK(%edx),%ecx + movl %ecx,P_RLINK(%eax) + movl %eax,P_RLINK(%edx) + movl %eax,P_LINK(%ecx) + ret + +set2: .asciz "setrq" + +/* + * Remrq(p) + * + * Call should be made at spl6(). + */ +ENTRY(remrq) + movl 4(%esp),%eax + movzbl P_PRI(%eax),%edx + shrl $2,%edx + btrl %edx,_whichqs # clear full bit, panic if clear already + jb rem1 + pushl $rem3 + call _panic +rem1: + pushl %edx + movl P_LINK(%eax),%ecx # unlink process + movl P_RLINK(%eax),%edx + movl %edx,P_RLINK(%ecx) + movl P_RLINK(%eax),%ecx + movl P_LINK(%eax),%edx + movl %edx,P_LINK(%ecx) + popl %edx + movl $_qs,%ecx + shll $3,%edx + addl %edx,%ecx + cmpl P_LINK(%ecx),%ecx # q still has something? + je rem2 + shrl $3,%edx # yes, set bit as still full + btsl %edx,_whichqs +rem2: + movl $0,P_RLINK(%eax) # zap reverse link to indicate off list + ret + +rem3: .asciz "remrq" +sw0: .asciz "swtch" + +/* + * When no processes are on the runq, Swtch branches to idle + * to wait for something to come ready. + */ + .globl Idle + ALIGN_TEXT +Idle: +sti_for_idle: + sti + SHOW_STI + ALIGN_TEXT +idle: + call _spl0 + cmpl $0,_whichqs + jne sw1 + hlt # wait for interrupt + jmp idle + + SUPERALIGN_TEXT /* so profiling doesn't lump Idle with swtch().. */ +badsw: + pushl $sw0 + call _panic + /*NOTREACHED*/ + +/* + * Swtch() + */ +ENTRY(swtch) + + incl _cnt+V_SWTCH + + /* switch to new process. first, save context as needed */ + + movl _curproc,%ecx + + /* if no process to save, don't bother */ + testl %ecx,%ecx + je sw1 + + movl P_ADDR(%ecx),%ecx + + movl (%esp),%eax # Hardware registers + movl %eax, PCB_EIP(%ecx) + movl %ebx, PCB_EBX(%ecx) + movl %esp, PCB_ESP(%ecx) + movl %ebp, PCB_EBP(%ecx) + movl %esi, PCB_ESI(%ecx) + movl %edi, PCB_EDI(%ecx) + +#ifdef NPX + /* have we used fp, and need a save? */ + mov _curproc,%eax + cmp %eax,_npxproc + jne 1f + pushl %ecx /* h/w bugs make saving complicated */ + leal PCB_SAVEFPU(%ecx),%eax + pushl %eax + call _npxsave /* do it in a big C function */ + popl %eax + popl %ecx +1: +#endif + + movl _CMAP2,%eax # save temporary map PTE + movl %eax,PCB_CMAP2(%ecx) # in our context + movl $0,_curproc # out of process + + # movw _cpl, %ax + # movw %ax, PCB_IML(%ecx) # save ipl + + /* save is done, now choose a new process or idle */ +sw1: + cli + SHOW_CLI + movl _whichqs,%edi +2: + # XXX - bsf is sloow + bsfl %edi,%eax # find a full q + je sti_for_idle # if none, idle + # XX update whichqs? +swfnd: + btrl %eax,%edi # clear q full status + jnb 2b # if it was clear, look for another + movl %eax,%ebx # save which one we are using + + shll $3,%eax + addl $_qs,%eax # select q + movl %eax,%esi + +#ifdef DIAGNOSTIC + cmpl P_LINK(%eax),%eax # linked to self? (e.g. not on list) + je badsw # not possible +#endif + + movl P_LINK(%eax),%ecx # unlink from front of process q + movl P_LINK(%ecx),%edx + movl %edx,P_LINK(%eax) + movl P_RLINK(%ecx),%eax + movl %eax,P_RLINK(%edx) + + cmpl P_LINK(%ecx),%esi # q empty + je 3f + btsl %ebx,%edi # nope, set to indicate full +3: + movl %edi,_whichqs # update q status + + movl $0,%eax + movl %eax,_want_resched + +#ifdef DIAGNOSTIC + cmpl %eax,P_WCHAN(%ecx) + jne badsw + cmpb $ SRUN,P_STAT(%ecx) + jne badsw +#endif + + movl %eax,P_RLINK(%ecx) /* isolate process to run */ + movl P_ADDR(%ecx),%edx + movl PCB_CR3(%edx),%ebx + + /* switch address space */ + movl %ebx,%cr3 + + /* restore context */ + movl PCB_EBX(%edx), %ebx + movl PCB_ESP(%edx), %esp + movl PCB_EBP(%edx), %ebp + movl PCB_ESI(%edx), %esi + movl PCB_EDI(%edx), %edi + movl PCB_EIP(%edx), %eax + movl %eax, (%esp) + + movl PCB_CMAP2(%edx),%eax # get temporary map + movl %eax,_CMAP2 # reload temporary map PTE + + movl %ecx,_curproc # into next process + movl %edx,_curpcb + + pushl %edx # save p to return +/* + * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1? + * I think restoring the cpl is unnecessary, but we must turn off the cli + * now that spl*() don't do it as a side affect. + */ + pushl PCB_IML(%edx) + sti + SHOW_STI +#if 0 + call _splx +#endif + addl $4,%esp +/* + * XXX - 0.0 gets here via swtch_to_inactive(). I think 0.1 gets here in the + * same way. Better return a value. + */ + popl %eax # return (p); + ret + +ENTRY(mvesp) + movl %esp,%eax + ret +/* + * struct proc *swtch_to_inactive(p) ; struct proc *p; + * + * At exit of a process, move off the address space of the + * process and onto a "safe" one. Then, on a temporary stack + * return and run code that disposes of the old state. + * Since this code requires a parameter from the "old" stack, + * pass it back as a return value. + */ +ENTRY(swtch_to_inactive) + popl %edx # old pc + popl %eax # arg, our return value + movl _IdlePTD,%ecx + movl %ecx,%cr3 # good bye address space + #write buffer? + movl $tmpstk-4,%esp # temporary stack, compensated for call + jmp %edx # return, execute remainder of cleanup + +/* + * savectx(pcb, altreturn) + * Update pcb, saving current processor state and arranging + * for alternate return ala longjmp in swtch if altreturn is true. + */ +ENTRY(savectx) + movl 4(%esp), %ecx + movw _cpl, %ax + movw %ax, PCB_IML(%ecx) + movl (%esp), %eax + movl %eax, PCB_EIP(%ecx) + movl %ebx, PCB_EBX(%ecx) + movl %esp, PCB_ESP(%ecx) + movl %ebp, PCB_EBP(%ecx) + movl %esi, PCB_ESI(%ecx) + movl %edi, PCB_EDI(%ecx) + +#ifdef NPX + /* + * If npxproc == NULL, then the npx h/w state is irrelevant and the + * state had better already be in the pcb. This is true for forks + * but not for dumps (the old book-keeping with FP flags in the pcb + * always lost for dumps because the dump pcb has 0 flags). + * + * If npxproc != NULL, then we have to save the npx h/w state to + * npxproc's pcb and copy it to the requested pcb, or save to the + * requested pcb and reload. Copying is easier because we would + * have to handle h/w bugs for reloading. We used to lose the + * parent's npx state for forks by forgetting to reload. + */ + mov _npxproc,%eax + testl %eax,%eax + je 1f + + pushl %ecx + movl P_ADDR(%eax),%eax + leal PCB_SAVEFPU(%eax),%eax + pushl %eax + pushl %eax + call _npxsave + popl %eax + popl %eax + popl %ecx + + pushl %ecx + pushl $108+8*2 /* XXX h/w state size + padding */ + leal PCB_SAVEFPU(%ecx),%ecx + pushl %ecx + pushl %eax + call _bcopy + addl $12,%esp + popl %ecx +1: +#endif + + movl _CMAP2, %edx # save temporary map PTE + movl %edx, PCB_CMAP2(%ecx) # in our context + + cmpl $0, 8(%esp) + je 1f + movl %esp, %edx # relocate current sp relative to pcb + subl $_kstack, %edx # (sp is relative to kstack): + addl %edx, %ecx # pcb += sp - kstack; + movl %eax, (%ecx) # write return pc at (relocated) sp@ + # this mess deals with replicating register state gcc hides + movl 12(%esp),%eax + movl %eax,12(%ecx) + movl 16(%esp),%eax + movl %eax,16(%ecx) + movl 20(%esp),%eax + movl %eax,20(%ecx) + movl 24(%esp),%eax + movl %eax,24(%ecx) +1: + xorl %eax, %eax # return 0 + ret + +/* + * addupc(int pc, struct uprof *up, int ticks): + * update profiling information for the user process. + */ + +ENTRY(addupc) + pushl %ebp + movl %esp,%ebp + movl 12(%ebp),%edx /* up */ + movl 8(%ebp),%eax /* pc */ + + subl PR_OFF(%edx),%eax /* pc -= up->pr_off */ + jl L1 /* if (pc < 0) return */ + + shrl $1,%eax /* praddr = pc >> 1 */ + imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */ + shrl $15,%eax /* praddr = praddr << 15 */ + andl $-2,%eax /* praddr &= ~1 */ + + cmpl PR_SIZE(%edx),%eax /* if (praddr > up->pr_size) return */ + ja L1 + +/* addl %eax,%eax /* praddr -> word offset */ + addl PR_BASE(%edx),%eax /* praddr += up-> pr_base */ + movl 16(%ebp),%ecx /* ticks */ + + movl _curpcb,%edx + movl $proffault,PCB_ONFAULT(%edx) + addl %ecx,(%eax) /* storage location += ticks */ + movl $0,PCB_ONFAULT(%edx) +L1: + leave + ret + + ALIGN_TEXT +proffault: + /* if we get a fault, then kill profiling all together */ + movl $0,PCB_ONFAULT(%edx) /* squish the fault handler */ + movl 12(%ebp),%ecx + movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */ + leave + ret + + # To be done: + ENTRY(astoff) + ret + + .data + ALIGN_DATA + .globl _cyloffset, _curpcb +_cyloffset: .long 0 + .globl _proc0paddr +_proc0paddr: .long 0 +LF: .asciz "swtch %x" + ALIGN_DATA + +#if 0 +#define PANIC(msg) xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \ + call _panic; MSG(msg) +#define PRINTF(n,msg) pushal ; nop ; pushl 1f; call _printf; MSG(msg) ; \ + popl %eax ; popal +#define MSG(msg) .data; 1: .asciz msg; ALIGN_DATA; .text +#endif /* 0 */ + +/* + * Trap and fault vector routines + * + * XXX - debugger traps are now interrupt gates so at least bdb doesn't lose + * control. The sti's give the standard losing behaviour for ddb and kgdb. + */ +#define IDTVEC(name) ALIGN_TEXT; .globl _X/**/name; _X/**/name: +#define TRAP(a) pushl $(a) ; jmp alltraps +#ifdef KGDB +#define BPTTRAP(a) sti; pushl $(a) ; jmp bpttraps +#else +#define BPTTRAP(a) sti; TRAP(a) +#endif + + .text +IDTVEC(div) + pushl $0; TRAP(T_DIVIDE) +IDTVEC(dbg) +#ifdef BDBTRAP + BDBTRAP(dbg) +#endif + pushl $0; BPTTRAP(T_TRCTRAP) +IDTVEC(nmi) + pushl $0; TRAP(T_NMI) +IDTVEC(bpt) +#ifdef BDBTRAP + BDBTRAP(bpt) +#endif + pushl $0; BPTTRAP(T_BPTFLT) +IDTVEC(ofl) + pushl $0; TRAP(T_OFLOW) +IDTVEC(bnd) + pushl $0; TRAP(T_BOUND) +IDTVEC(ill) + pushl $0; TRAP(T_PRIVINFLT) +IDTVEC(dna) + pushl $0; TRAP(T_DNA) +IDTVEC(dble) + TRAP(T_DOUBLEFLT) + /*PANIC("Double Fault");*/ +IDTVEC(fpusegm) + pushl $0; TRAP(T_FPOPFLT) +IDTVEC(tss) + TRAP(T_TSSFLT) + /*PANIC("TSS not valid");*/ +IDTVEC(missing) + TRAP(T_SEGNPFLT) +IDTVEC(stk) + TRAP(T_STKFLT) +IDTVEC(prot) + TRAP(T_PROTFLT) +IDTVEC(page) + TRAP(T_PAGEFLT) +IDTVEC(rsvd) + pushl $0; TRAP(T_RESERVED) +IDTVEC(fpu) +#ifdef NPX + /* + * Handle like an interrupt so that we can call npxintr to clear the + * error. It would be better to handle npx interrupts as traps but + * this is difficult for nested interrupts. + */ + pushl $0 /* dummy error code */ + pushl $T_ASTFLT + pushal + nop /* silly, the bug is for popal and it only + * bites when the next instruction has a + * complicated address mode */ + pushl %ds + pushl %es /* now the stack frame is a trap frame */ + movl $KDSEL,%eax + movl %ax,%ds + movl %ax,%es + pushl _cpl + pushl $0 /* dummy unit to finish building intr frame */ + incl _cnt+V_TRAP + call _npxintr + jmp doreti +#else + pushl $0; TRAP(T_ARITHTRAP) +#endif + /* 17 - 31 reserved for future exp */ +IDTVEC(rsvd0) + pushl $0; TRAP(17) +IDTVEC(rsvd1) + pushl $0; TRAP(18) +IDTVEC(rsvd2) + pushl $0; TRAP(19) +IDTVEC(rsvd3) + pushl $0; TRAP(20) +IDTVEC(rsvd4) + pushl $0; TRAP(21) +IDTVEC(rsvd5) + pushl $0; TRAP(22) +IDTVEC(rsvd6) + pushl $0; TRAP(23) +IDTVEC(rsvd7) + pushl $0; TRAP(24) +IDTVEC(rsvd8) + pushl $0; TRAP(25) +IDTVEC(rsvd9) + pushl $0; TRAP(26) +IDTVEC(rsvd10) + pushl $0; TRAP(27) +IDTVEC(rsvd11) + pushl $0; TRAP(28) +IDTVEC(rsvd12) + pushl $0; TRAP(29) +IDTVEC(rsvd13) + pushl $0; TRAP(30) +IDTVEC(rsvd14) + pushl $0; TRAP(31) + + SUPERALIGN_TEXT +alltraps: + pushal + nop + pushl %ds + pushl %es + movl $KDSEL,%eax + movl %ax,%ds + movl %ax,%es +calltrap: + incl _cnt+V_TRAP + call _trap + /* + * Return through doreti to handle ASTs. Have to change trap frame + * to interrupt frame. + */ + movl $T_ASTFLT,4+4+32(%esp) /* new trap type (err code not used) */ + pushl _cpl + pushl $0 /* dummy unit */ + jmp doreti + +#ifdef KGDB +/* + * This code checks for a kgdb trap, then falls through + * to the regular trap code. + */ + ALIGN_TEXT +bpttraps: + pushal + nop + pushl %es + pushl %ds + movl $KDSEL,%eax + movl %ax,%ds + movl %ax,%es + testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp) + # non-kernel mode? + jne calltrap # yes + call _kgdb_trap_glue + jmp calltrap +#endif + +/* + * Call gate entry for syscall + */ + + SUPERALIGN_TEXT +IDTVEC(syscall) + pushfl # only for stupid carry bit and more stupid wait3 cc kludge + # XXX - also for direction flag (bzero, etc. clear it) + pushal # only need eax,ecx,edx - trap resaves others + nop + movl $KDSEL,%eax # switch to kernel segments + movl %ax,%ds + movl %ax,%es + incl _cnt+V_SYSCALL # kml 3/25/93 + call _syscall + /* + * Return through doreti to handle ASTs. Have to change syscall frame + * to interrupt frame. + * + * XXX - we should have set up the frame earlier to avoid the + * following popal/pushal (not much can be done to avoid shuffling + * the flags). Consistent frames would simplify things all over. + */ + movl 32+0(%esp),%eax /* old flags, shuffle to above cs:eip */ + movl 32+4(%esp),%ebx /* `int' frame should have been ef, eip, cs */ + movl 32+8(%esp),%ecx + movl %ebx,32+0(%esp) + movl %ecx,32+4(%esp) + movl %eax,32+8(%esp) + popal + nop + pushl $0 /* dummy error code */ + pushl $T_ASTFLT + pushal + nop + movl __udatasel,%eax /* switch back to user segments */ + push %eax /* XXX - better to preserve originals? */ + push %eax + pushl _cpl + pushl $0 + jmp doreti + +ENTRY(htonl) +ENTRY(ntohl) + movl 4(%esp),%eax +#ifdef i486 + /* XXX */ + /* Since Gas 1.38 does not grok bswap this has been coded as the + * equivalent bytes. This can be changed back to bswap when we + * upgrade to a newer version of Gas */ + /* bswap %eax */ + .byte 0x0f + .byte 0xc8 +#else + xchgb %al,%ah + roll $16,%eax + xchgb %al,%ah +#endif + ret + +ENTRY(htons) +ENTRY(ntohs) + movzwl 4(%esp),%eax + xchgb %al,%ah + ret + +#ifdef SHOW_A_LOT + +/* + * 'show_bits' was too big when defined as a macro. The line length for some + * enclosing macro was too big for gas. Perhaps the code would have blown + * the cache anyway. + */ + + ALIGN_TEXT +show_bits: + pushl %eax + SHOW_BIT(0) + SHOW_BIT(1) + SHOW_BIT(2) + SHOW_BIT(3) + SHOW_BIT(4) + SHOW_BIT(5) + SHOW_BIT(6) + SHOW_BIT(7) + SHOW_BIT(8) + SHOW_BIT(9) + SHOW_BIT(10) + SHOW_BIT(11) + SHOW_BIT(12) + SHOW_BIT(13) + SHOW_BIT(14) + SHOW_BIT(15) + popl %eax + ret + + .data +bit_colors: + .byte GREEN,RED,0,0 + .text + +#endif /* SHOW_A_LOT */ + +#include "i386/isa/vector.s" +#include "i386/isa/icu.s" diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c new file mode 100644 index 000000000000..f0351a7ddf9e --- /dev/null +++ b/sys/i386/i386/machdep.c @@ -0,0 +1,1131 @@ +/*- + * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. + * Copyright (c) 1992 Terrence R. Lambert. + * 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. + * + * @(#)machdep.c 7.4 (Berkeley) 6/3/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 5 00158 + * -------------------- ----- ---------------------- + * + * 15 Aug 92 William Jolitz Large memory bug + * 15 Aug 92 Terry Lambert Fixed CMOS RAM size bug + * 25 Mar 93 Sean Eric Fagan Added #ifdef HZ around microtime for + * the new microtime.s routine + * 08 Apr 93 Andrew Herbert Fixes for kmem_alloc panics + * 20 Apr 93 Bruce Evans New npx-0.5 code + * 25 Apr 93 Bruce Evans New intr-0.1 code + */ +static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/i386/RCS/machdep.c,v 1.2 92/01/21 14:22:09 william Exp Locker: root $"; + + +#include <stddef.h> +#include "param.h" +#include "systm.h" +#include "signalvar.h" +#include "kernel.h" +#include "proc.h" +#include "user.h" +#include "buf.h" +#include "reboot.h" +#include "conf.h" +#include "file.h" +#include "callout.h" +#include "malloc.h" +#include "mbuf.h" +#include "msgbuf.h" +#include "net/netisr.h" + +#include "vm/vm.h" +#include "vm/vm_kern.h" +#include "vm/vm_page.h" + +extern vm_offset_t avail_end; + +#include "machine/cpu.h" +#include "machine/reg.h" +#include "machine/psl.h" +#include "machine/specialreg.h" +#include "i386/isa/rtc.h" + + +#define EXPECT_BASEMEM 640 /* The expected base memory*/ +#define INFORM_WAIT 1 /* Set to pause berfore crash in weird cases*/ + +/* + * 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; /* set when safe to use msgbuf */ +extern int freebufspace; + +/* + * Machine-dependent startup code + */ +int boothowto = 0, Maxmem = 0; +long dumplo; +int physmem, maxmem; +extern int bootdev; +#ifdef SMALL +extern int forcemaxmem; +#endif +int biosmem; + +extern cyloffset; + +cpu_startup() +{ + register int unixsize; + register unsigned i; + register struct pte *pte; + int mapaddr, j; + register caddr_t v; + int maxbufs, base, residual; + extern long Usrptsize; + vm_offset_t minaddr, maxaddr; + vm_size_t size; + int firstaddr; + + /* + * Initialize error message buffer (at end of core). + */ + + /* avail_end was pre-decremented in pmap_bootstrap to compensate */ + for (i = 0; i < btoc(sizeof (struct msgbuf)); i++) + pmap_enter(pmap_kernel(), msgbufp, avail_end + i * NBPG, + VM_PROT_ALL, TRUE); + msgbufmapped = 1; + +#ifdef KDB + kdb_init(); /* startup kernel debugger */ +#endif + /* + * Good {morning,afternoon,evening,night}. + */ + /*printf(version); + printf("real mem = %d\n", ctob(physmem));*/ + + /* + * 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. + * As pages of memory are allocated and cleared, + * "firstaddr" is incremented. + * An index into the kernel page table corresponding to the + * virtual memory address maintained in "v" is kept in "mapaddr". + */ + + /* + * Make two passes. The first pass calculates how much memory is + * needed and allocates it. The second pass assigns virtual + * addresses to the various data structures. + */ + firstaddr = 0; +again: + v = (caddr_t)firstaddr; + +#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))) + valloc(callout, struct callout, ncallout); +#ifdef SYSVSHM + valloc(shmsegs, struct shmid_ds, shminfo.shmmni); +#endif + /* + * Determine how many buffers to allocate. + * Use 10% of memory for the first 2 Meg, 5% of the remaining + * memory. Insure a minimum of 16 buffers. + * We allocate 1/2 as many swap buffer headers as file i/o buffers. + */ + if (bufpages == 0) + if (physmem < (2 * 1024 * 1024)) + bufpages = physmem / 10 / CLSIZE; + else + bufpages = ((2 * 1024 * 1024 + physmem) / 20) / CLSIZE; + /* + * 15 Aug 92 William Jolitz bufpages fix for too large + */ + bufpages = min( NKMEMCLUSTERS*2/5, bufpages); + + if (nbuf == 0) { + nbuf = bufpages / 2; + if (nbuf < 16) + nbuf = 16; + } + freebufspace = bufpages * NBPG; + 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); + + /* + * End of first pass, size has been calculated so allocate memory + */ + if (firstaddr == 0) { + size = (vm_size_t)(v - firstaddr); + firstaddr = (int)kmem_alloc(kernel_map, round_page(size)); + if (firstaddr == 0) + panic("startup: no room for tables"); + goto again; + } + /* + * End of second pass, addresses have been assigned + */ + if ((vm_size_t)(v - firstaddr) != size) + panic("startup: table size inconsistency"); + /* + * Allocate a submap for buffer space allocations. + */ + buffer_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, + bufpages*NBPG, 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]; + + /*printf("avail mem = %d\n", ptoa(vm_page_free_count));*/ + + /* + * 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(); +} + +#ifdef PGINPROF +/* + * Return the difference (in microseconds) + * between the current time and a previous + * time as represented by the arguments. + * If there is a pending clock interrupt + * which has not been serviced due to high + * ipl, return error code. + */ +/*ARGSUSED*/ +vmtime(otime, olbolt, oicr) + register int otime, olbolt, oicr; +{ + + return (((time.tv_sec-otime)*60 + lbolt-olbolt)*16667); +} +#endif + +struct sigframe { + int sf_signum; + int sf_code; + struct sigcontext *sf_scp; + sig_t sf_handler; + int sf_eax; + int sf_edx; + int sf_ecx; + struct sigcontext sf_sc; +} ; + +extern int kstack[]; + +/* + * Send an interrupt to process. + * + * Stack is set up to allow sigcode stored + * in u. to call routine, followed by kcall + * to sigreturn routine below. After sigreturn + * resets the signal mask, the stack, and the + * frame pointer, it returns to the user + * specified pc, psl. + */ +void +sendsig(catcher, sig, mask, code) + sig_t catcher; + int sig, mask; + unsigned code; +{ + register struct proc *p = curproc; + register int *regs; + register struct sigframe *fp; + struct sigacts *ps = p->p_sigacts; + int oonstack, frmtrap; + + regs = p->p_regs; + oonstack = ps->ps_onstack; + frmtrap = curpcb->pcb_flags & FM_TRAP; + /* + * Allocate and validate space for the signal handler + * context. Note that if the stack is in P0 space, the + * call to grow() is a nop, and the useracc() check + * will fail if the process has not already allocated + * the space with a `brk'. + */ + if (!ps->ps_onstack && (ps->ps_sigonstack & sigmask(sig))) { + fp = (struct sigframe *)(ps->ps_sigsp + - sizeof(struct sigframe)); + ps->ps_onstack = 1; + } else { + if (frmtrap) + fp = (struct sigframe *)(regs[tESP] + - sizeof(struct sigframe)); + else + fp = (struct sigframe *)(regs[sESP] + - sizeof(struct sigframe)); + } + + if ((unsigned)fp <= (unsigned)p->p_vmspace->vm_maxsaddr + MAXSSIZ - ctob(p->p_vmspace->vm_ssize)) + (void)grow(p, (unsigned)fp); + + if (useracc((caddr_t)fp, sizeof (struct sigframe), B_WRITE) == 0) { + /* + * 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. + */ + fp->sf_signum = sig; + fp->sf_code = code; + fp->sf_scp = &fp->sf_sc; + fp->sf_handler = catcher; + + /* save scratch registers */ + if(frmtrap) { + fp->sf_eax = regs[tEAX]; + fp->sf_edx = regs[tEDX]; + fp->sf_ecx = regs[tECX]; + } else { + fp->sf_eax = regs[sEAX]; + fp->sf_edx = regs[sEDX]; + fp->sf_ecx = regs[sECX]; + } + /* + * Build the signal context to be used by sigreturn. + */ + fp->sf_sc.sc_onstack = oonstack; + fp->sf_sc.sc_mask = mask; + if(frmtrap) { + fp->sf_sc.sc_sp = regs[tESP]; + fp->sf_sc.sc_fp = regs[tEBP]; + fp->sf_sc.sc_pc = regs[tEIP]; + fp->sf_sc.sc_ps = regs[tEFLAGS]; + regs[tESP] = (int)fp; + regs[tEIP] = (int)((struct pcb *)kstack)->pcb_sigc; + } else { + fp->sf_sc.sc_sp = regs[sESP]; + fp->sf_sc.sc_fp = regs[sEBP]; + fp->sf_sc.sc_pc = regs[sEIP]; + fp->sf_sc.sc_ps = regs[sEFLAGS]; + regs[sESP] = (int)fp; + regs[sEIP] = (int)((struct pcb *)kstack)->pcb_sigc; + } +} + +/* + * 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. + */ +sigreturn(p, uap, retval) + struct proc *p; + struct args { + struct sigcontext *sigcntxp; + } *uap; + int *retval; +{ + register struct sigcontext *scp; + register struct sigframe *fp; + register int *regs = p->p_regs; + + + /* + * (XXX old comment) regs[sESP] points to the return address. + * The user scp pointer is above that. + * The return address is faked in the signal trampoline code + * for consistency. + */ + scp = uap->sigcntxp; + fp = (struct sigframe *) + ((caddr_t)scp - offsetof(struct sigframe, sf_sc)); + + if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0) + return(EINVAL); + + /* restore scratch registers */ + regs[sEAX] = fp->sf_eax ; + regs[sEDX] = fp->sf_edx ; + regs[sECX] = fp->sf_ecx ; + + if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0) + return(EINVAL); +#ifdef notyet + if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO) { + return(EINVAL); + } +#endif + p->p_sigacts->ps_onstack = scp->sc_onstack & 01; + p->p_sigmask = scp->sc_mask &~ + (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP)); + regs[sEBP] = scp->sc_fp; + regs[sESP] = scp->sc_sp; + regs[sEIP] = scp->sc_pc; + regs[sEFLAGS] = scp->sc_ps; + return(EJUSTRETURN); +} + +int waittime = -1; +struct pcb dumppcb; + +boot(arghowto) + int arghowto; +{ + register long dummy; /* r12 is reserved */ + register int howto; /* r11 == how to boot */ + register int devtype; /* r10 == major of root dev */ + extern char *panicstr; + extern int cold; + int nomsg = 1; + + if(cold) { + printf("hit reset please"); + for(;;); + } + howto = arghowto; + if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) { + register struct buf *bp; + int iter, nbusy; + + waittime = 0; + (void) splnet(); + /* + * Release inodes held by texts before update. + */ + if (panicstr == 0) + vnode_pager_umount(NULL); + sync((struct sigcontext *)0); + + for (iter = 0; iter < 20; iter++) { + nbusy = 0; + for (bp = &buf[nbuf]; --bp >= buf; ) + if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY) + nbusy++; + if (nbusy == 0) + break; + if (nomsg) { + printf("updating disks before rebooting... "); + nomsg = 0; + } + /* printf("%d ", nbusy); */ + DELAY(40000 * iter); + } + if (nbusy) + printf(" failed!\n"); + else if (nomsg == 0) + printf("succeded.\n"); + DELAY(10000); /* wait for printf to finish */ + } + splhigh(); + devtype = major(rootdev); + if (howto&RB_HALT) { + pg("\nThe operating system has halted. Please press any key to reboot.\n\n"); + } else { + if (howto & RB_DUMP) { + savectx(&dumppcb, 0); + dumppcb.pcb_ptd = rcr3(); + dumpsys(); + /*NOTREACHED*/ + } + } +#ifdef lint + dummy = 0; dummy = dummy; + printf("howto %d, devtype %d\n", arghowto, devtype); +#endif + cpu_reset(); + for(;;) ; + /*NOTREACHED*/ +} + +int dumpmag = 0x8fca0101; /* magic number for savecore */ +int dumpsize = 0; /* also for savecore */ +/* + * 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() +{ + + if (dumpdev == NODEV) + return; + if ((minor(dumpdev)&07) != 1) + return; + printf("\nThe operating system is saving a copy of RAM memory to device %x, offset %d\n\ +(hit any key to abort): [ amount left to save (MB) ] ", dumpdev, dumplo); + dumpsize = physmem; + switch ((*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; + + case EINTR: + printf("-- aborted from console\n"); + break; + + default: + printf(" succeeded\n"); + break; + } + printf("system rebooting.\n\n"); + DELAY(10000); +} + +#ifdef HZ +/* + * If HZ is defined we use this code, otherwise the code in + * /sys/i386/i386/microtime.s is used. The othercode only works + * for HZ=100. + */ +microtime(tvp) + register struct timeval *tvp; +{ + int s = splhigh(); + + *tvp = time; + tvp->tv_usec += tick; + while (tvp->tv_usec > 1000000) { + tvp->tv_sec++; + tvp->tv_usec -= 1000000; + } + splx(s); +} +#endif /* HZ */ + +physstrat(bp, strat, prio) + struct buf *bp; + int (*strat)(), prio; +{ + register int s; + caddr_t baddr; + + /* + * vmapbuf clobbers b_addr so we must remember it so that it + * can be restored after vunmapbuf. This is truely rude, we + * should really be storing this in a field in the buf struct + * but none are available and I didn't want to add one at + * this time. Note that b_addr for dirty page pushes is + * restored in vunmapbuf. (ugh!) + */ + baddr = bp->b_un.b_addr; + vmapbuf(bp); + (*strat)(bp); + /* pageout daemon doesn't wait for pushed pages */ + if (bp->b_flags & B_DIRTY) + return; + s = splbio(); + while ((bp->b_flags & B_DONE) == 0) + sleep((caddr_t)bp, prio); + splx(s); + vunmapbuf(bp); + bp->b_un.b_addr = baddr; +} + +initcpu() +{ +} + +/* + * Clear registers on exec + */ +setregs(p, entry) + struct proc *p; + u_long entry; +{ + + p->p_regs[sEBP] = 0; /* bottom of the fp chain */ + p->p_regs[sEIP] = entry; + + p->p_addr->u_pcb.pcb_flags = 0; /* no fp at all */ + load_cr0(rcr0() | CR0_TS); /* start emulating */ +#ifdef NPX + npxinit(__INITIAL_NPXCW__); +#endif +} + +/* + * Initialize 386 and configure to run kernel + */ + +/* + * Initialize segments & interrupt table + */ + + +#define GNULL_SEL 0 /* Null Descriptor */ +#define GCODE_SEL 1 /* Kernel Code Descriptor */ +#define GDATA_SEL 2 /* Kernel Data Descriptor */ +#define GLDT_SEL 3 /* LDT - eventually one per process */ +#define GTGATE_SEL 4 /* Process task switch gate */ +#define GPANIC_SEL 5 /* Task state to consider panic from */ +#define GPROC0_SEL 6 /* Task state process slot zero and up */ +#define NGDT GPROC0_SEL+1 + +union descriptor gdt[GPROC0_SEL+1]; + +/* interrupt descriptor table */ +struct gate_descriptor idt[NIDT]; + +/* local descriptor table */ +union descriptor ldt[5]; +#define LSYS5CALLS_SEL 0 /* forced by intel BCS */ +#define LSYS5SIGR_SEL 1 + +#define L43BSDCALLS_SEL 2 /* notyet */ +#define LUCODE_SEL 3 +#define LUDATA_SEL 4 +/* seperate stack, es,fs,gs sels ? */ +/* #define LPOSIXCALLS_SEL 5 /* notyet */ + +struct i386tss tss, panic_tss; + +extern struct user *proc0paddr; + +/* software prototypes -- in more palitable form */ +struct soft_segment_descriptor gdt_segs[] = { + /* Null Descriptor */ +{ 0x0, /* segment base address */ + 0x0, /* length - all address space */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0,0, + 0, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Code Descriptor for kernel */ +{ 0x0, /* segment base address */ + 0xfffff, /* length - all address space */ + SDT_MEMERA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 1, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, + /* Data Descriptor for kernel */ +{ 0x0, /* segment base address */ + 0xfffff, /* length - all address space */ + SDT_MEMRWA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 1, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, + /* LDT Descriptor */ +{ (int) ldt, /* segment base address */ + sizeof(ldt)-1, /* length - all address space */ + SDT_SYSLDT, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 0, /* unused - default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Null Descriptor - Placeholder */ +{ 0x0, /* segment base address */ + 0x0, /* length - all address space */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0,0, + 0, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Panic Tss Descriptor */ +{ (int) &panic_tss, /* segment base address */ + sizeof(tss)-1, /* length - all address space */ + SDT_SYS386TSS, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 0, /* unused - default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Proc 0 Tss Descriptor */ +{ (int) kstack, /* segment base address */ + sizeof(tss)-1, /* length - all address space */ + SDT_SYS386TSS, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 0, /* unused - default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }}; + +struct soft_segment_descriptor ldt_segs[] = { + /* Null Descriptor - overwritten by call gate */ +{ 0x0, /* segment base address */ + 0x0, /* length - all address space */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0,0, + 0, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Null Descriptor - overwritten by call gate */ +{ 0x0, /* segment base address */ + 0x0, /* length - all address space */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0,0, + 0, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Null Descriptor - overwritten by call gate */ +{ 0x0, /* segment base address */ + 0x0, /* length - all address space */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0,0, + 0, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* Code Descriptor for user */ +{ 0x0, /* segment base address */ + 0xfffff, /* length - all address space */ + SDT_MEMERA, /* segment type */ + SEL_UPL, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 1, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, + /* Data Descriptor for user */ +{ 0x0, /* segment base address */ + 0xfffff, /* length - all address space */ + SDT_MEMRWA, /* segment type */ + SEL_UPL, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0,0, + 1, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ } }; + +setidt(idx, func, typ, dpl) char *func; { + struct gate_descriptor *ip = idt + idx; + + ip->gd_looffset = (int)func; + ip->gd_selector = 8; + ip->gd_stkcpy = 0; + ip->gd_xx = 0; + ip->gd_type = typ; + ip->gd_dpl = dpl; + ip->gd_p = 1; + ip->gd_hioffset = ((int)func)>>16 ; +} + +#define IDTVEC(name) __CONCAT(X, name) +extern IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl), + IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm), + IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), + IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0), + IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4), + IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8), + IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12), + IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(rsvd14), IDTVEC(syscall); + +int lcr0(), lcr3(), rcr0(), rcr2(); +int _udatasel, _ucodesel, _gsel_tss; + +init386(first) +{ + extern ssdtosd(), lgdt(), lidt(), lldt(), etext; + int x, *pi; + unsigned biosbasemem, biosextmem; + struct gate_descriptor *gdp; + extern int sigcode,szsigcode; + /* table descriptors - used to load tables by microp */ + struct region_descriptor r_gdt, r_idt; + int pagesinbase, pagesinext; + + + proc0.p_addr = proc0paddr; + + /* + * Initialize the console before we print anything out. + */ + + cninit (KERNBASE+0xa0000); + + /* make gdt memory segments */ + gdt_segs[GCODE_SEL].ssd_limit = btoc((int) &etext + NBPG); + for (x=0; x < NGDT; x++) ssdtosd(gdt_segs+x, gdt+x); + /* make ldt memory segments */ + ldt_segs[LUCODE_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS); + ldt_segs[LUDATA_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS); + /* Note. eventually want private ldts per process */ + for (x=0; x < 5; x++) ssdtosd(ldt_segs+x, ldt+x); + + /* exceptions */ + setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL); + setidt(1, &IDTVEC(dbg), SDT_SYS386TGT, SEL_KPL); + setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL); + setidt(3, &IDTVEC(bpt), SDT_SYS386TGT, SEL_UPL); + setidt(4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_KPL); + setidt(5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL); + setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL); + setidt(7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL); + setidt(8, &IDTVEC(dble), SDT_SYS386TGT, SEL_KPL); + setidt(9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL); + setidt(10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL); + setidt(11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL); + setidt(12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL); + setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL); + setidt(14, &IDTVEC(page), SDT_SYS386TGT, SEL_KPL); + setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL); + setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL); + setidt(17, &IDTVEC(rsvd0), SDT_SYS386TGT, SEL_KPL); + setidt(18, &IDTVEC(rsvd1), SDT_SYS386TGT, SEL_KPL); + setidt(19, &IDTVEC(rsvd2), SDT_SYS386TGT, SEL_KPL); + setidt(20, &IDTVEC(rsvd3), SDT_SYS386TGT, SEL_KPL); + setidt(21, &IDTVEC(rsvd4), SDT_SYS386TGT, SEL_KPL); + setidt(22, &IDTVEC(rsvd5), SDT_SYS386TGT, SEL_KPL); + setidt(23, &IDTVEC(rsvd6), SDT_SYS386TGT, SEL_KPL); + setidt(24, &IDTVEC(rsvd7), SDT_SYS386TGT, SEL_KPL); + setidt(25, &IDTVEC(rsvd8), SDT_SYS386TGT, SEL_KPL); + setidt(26, &IDTVEC(rsvd9), SDT_SYS386TGT, SEL_KPL); + setidt(27, &IDTVEC(rsvd10), SDT_SYS386TGT, SEL_KPL); + setidt(28, &IDTVEC(rsvd11), SDT_SYS386TGT, SEL_KPL); + setidt(29, &IDTVEC(rsvd12), SDT_SYS386TGT, SEL_KPL); + setidt(30, &IDTVEC(rsvd13), SDT_SYS386TGT, SEL_KPL); + setidt(31, &IDTVEC(rsvd14), SDT_SYS386TGT, SEL_KPL); + +#include "isa.h" +#if NISA >0 + isa_defaultirq(); +#endif + + r_gdt.rd_limit = sizeof(gdt)-1; + r_gdt.rd_base = (int) gdt; + lgdt(&r_gdt); + r_idt.rd_limit = sizeof(idt)-1; + r_idt.rd_base = (int) idt; + lidt(&r_idt); + lldt(GSEL(GLDT_SEL, SEL_KPL)); + +#include "ddb.h" +#if NDDB > 0 + kdb_init(); + if (boothowto & RB_KDB) + Debugger(); +#endif + + /* Use BIOS values stored in RTC CMOS RAM, since probing + * breaks certain 386 AT relics. + */ + biosbasemem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8); + biosextmem = rtcin(RTC_EXTLO)+ (rtcin(RTC_EXTHI)<<8); +/*printf("bios base %d ext %d ", biosbasemem, biosextmem);*/ + + /* + * 15 Aug 92 Terry Lambert The real fix for the CMOS bug + */ + if( biosbasemem != EXPECT_BASEMEM) { + printf( "Warning: Base memory %dK, assuming %dK\n", biosbasemem, EXPECT_BASEMEM); + biosbasemem = EXPECT_BASEMEM; /* assume base*/ + } + + if( biosextmem > 65536) { + printf( "Warning: Extended memory %dK(>64M), assuming 0K\n", biosextmem); + biosextmem = 0; /* assume none*/ + } + + /* + * Go into normal calculation; Note that we try to run in 640K, and + * that invalid CMOS values of non 0xffff are no longer a cause of + * ptdi problems. I have found a gutted kernel can run in 640K. + */ + pagesinbase = 640/4 - first/NBPG; + pagesinext = biosextmem/4; + /* use greater of either base or extended memory. do this + * until I reinstitue discontiguous allocation of vm_page + * array. + */ + if (pagesinbase > pagesinext) + Maxmem = 640/4; + else { + Maxmem = pagesinext + 0x100000/NBPG; + first = 0x100000; /* skip hole */ + } + + /* This used to explode, since Maxmem used to be 0 for bas CMOS*/ + maxmem = Maxmem - 1; /* highest page of usable memory */ + physmem = maxmem; /* number of pages of physmem addr space */ +/*printf("using first 0x%x to 0x%x\n ", first, maxmem*NBPG);*/ + if (maxmem < 2048/4) { + printf("Too little RAM memory. Warning, running in degraded mode.\n"); +#ifdef INFORM_WAIT + /* + * People with less than 2 Meg have to hit return; this way + * we see the messages and can tell them why they blow up later. + * If they get working well enough to recompile, they can unset + * the flag; otherwise, it's a toy and they have to lump it. + */ + getchar(); /* kernel getchar in /sys/i386/isa/pccons.c*/ +#endif /* !INFORM_WAIT*/ + } + /* + * End of CMOS bux fix + */ + + /* call pmap initialization to make new kernel address space */ + pmap_bootstrap (first, 0); + /* now running on new page tables, configured,and u/iom is accessible */ + + /* make a initial tss so microp can get interrupt stack on syscall! */ + proc0.p_addr->u_pcb.pcb_tss.tss_esp0 = (int) kstack + UPAGES*NBPG; + proc0.p_addr->u_pcb.pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ; + _gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); + ltr(_gsel_tss); + + /* make a call gate to reenter kernel with */ + gdp = &ldt[LSYS5CALLS_SEL].gd; + + x = (int) &IDTVEC(syscall); + gdp->gd_looffset = x++; + gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL); + gdp->gd_stkcpy = 0; + gdp->gd_type = SDT_SYS386CGT; + gdp->gd_dpl = SEL_UPL; + gdp->gd_p = 1; + gdp->gd_hioffset = ((int) &IDTVEC(syscall)) >>16; + + /* transfer to user mode */ + + _ucodesel = LSEL(LUCODE_SEL, SEL_UPL); + _udatasel = LSEL(LUDATA_SEL, SEL_UPL); + + /* setup proc 0's pcb */ + bcopy(&sigcode, proc0.p_addr->u_pcb.pcb_sigc, szsigcode); + proc0.p_addr->u_pcb.pcb_flags = 0; + proc0.p_addr->u_pcb.pcb_ptd = IdlePTD; +} + +extern struct pte *CMAP1, *CMAP2; +extern caddr_t CADDR1, CADDR2; +/* + * zero out physical memory + * specified in relocation units (NBPG bytes) + */ +clearseg(n) { + + *(int *)CMAP2 = PG_V | PG_KW | ctob(n); + load_cr3(rcr3()); + bzero(CADDR2,NBPG); + *(int *) CADDR2 = 0; +} + +/* + * copy a page of physical memory + * specified in relocation units (NBPG bytes) + */ +copyseg(frm, n) { + + *(int *)CMAP2 = PG_V | PG_KW | ctob(n); + load_cr3(rcr3()); + bcopy((void *)frm, (void *)CADDR2, NBPG); +} + +/* + * copy a page of physical memory + * specified in relocation units (NBPG bytes) + */ +physcopyseg(frm, to) { + + *(int *)CMAP1 = PG_V | PG_KW | ctob(frm); + *(int *)CMAP2 = PG_V | PG_KW | ctob(to); + load_cr3(rcr3()); + bcopy(CADDR1, CADDR2, NBPG); +} + +/*aston() { + schednetisr(NETISR_AST); +}*/ + +setsoftclock() { + schednetisr(NETISR_SCLK); +} + +/* + * insert an element into a queue + */ +#undef insque +_insque(element, head) + register struct prochd *element, *head; +{ + element->ph_link = head->ph_link; + head->ph_link = (struct proc *)element; + element->ph_rlink = (struct proc *)head; + ((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element; +} + +/* + * remove an element from a queue + */ +#undef remque +_remque(element) + register struct prochd *element; +{ + ((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink; + ((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link; + element->ph_rlink = (struct proc *)0; +} + +vmunaccess() {} + +/* + * Below written in C to allow access to debugging code + */ +copyinstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength; + void *toaddr, *fromaddr; { + int c,tally; + + tally = 0; + while (maxlength--) { + c = fubyte(fromaddr++); + if (c == -1) { + if(lencopied) *lencopied = tally; + return(EFAULT); + } + tally++; + *(char *)toaddr++ = (char) c; + if (c == 0){ + if(lencopied) *lencopied = (u_int)tally; + return(0); + } + } + if(lencopied) *lencopied = (u_int)tally; + return(ENAMETOOLONG); +} + +copyoutstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength; + void *fromaddr, *toaddr; { + int c; + int tally; + + tally = 0; + while (maxlength--) { + c = subyte(toaddr++, *(char *)fromaddr); + if (c == -1) return(EFAULT); + tally++; + if (*(char *)fromaddr++ == 0){ + if(lencopied) *lencopied = tally; + return(0); + } + } + if(lencopied) *lencopied = tally; + return(ENAMETOOLONG); +} + +copystr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength; + void *fromaddr, *toaddr; { + u_int tally; + + tally = 0; + while (maxlength--) { + *(u_char *)toaddr = *(u_char *)fromaddr++; + tally++; + if (*(u_char *)toaddr++ == 0) { + if(lencopied) *lencopied = tally; + return(0); + } + } + if(lencopied) *lencopied = tally; + return(ENAMETOOLONG); +} diff --git a/sys/i386/i386/math_emu.h b/sys/i386/i386/math_emu.h new file mode 100644 index 000000000000..537fba5641b8 --- /dev/null +++ b/sys/i386/i386/math_emu.h @@ -0,0 +1,154 @@ +/* + * linux/include/linux/math_emu.h + * + * (C) 1991 Linus Torvalds + */ +#ifndef _LINUX_MATH_EMU_H +#define _LINUX_MATH_EMU_H + +/*#define math_abort(x,y) \ +(((volatile void (*)(struct info *,unsigned int)) __math_abort)((x),(y)))*/ + +/* + * Gcc forces this stupid alignment problem: I want to use only two longs + * for the temporary real 64-bit mantissa, but then gcc aligns out the + * structure to 12 bytes which breaks things in math_emulate.c. Shit. I + * want some kind of "no-alignt" pragma or something. + */ + +typedef struct { + long a,b; + short exponent; +} temp_real; + +typedef struct { + short m0,m1,m2,m3; + short exponent; +} temp_real_unaligned; + +#define real_to_real(a,b) \ +((*(long long *) (b) = *(long long *) (a)),((b)->exponent = (a)->exponent)) + +typedef struct { + long a,b; +} long_real; + +typedef long short_real; + +typedef struct { + long a,b; + short sign; +} temp_int; + +struct swd { + int ie:1; + int de:1; + int ze:1; + int oe:1; + int ue:1; + int pe:1; + int sf:1; + int ir:1; + int c0:1; + int c1:1; + int c2:1; + int top:3; + int c3:1; + int b:1; +}; +struct i387_struct { + long cwd; + long swd; + long twd; + long fip; + long fcs; + long foo; + long fos; + long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ +}; + +#define I387 (*(struct i387_struct *)&(((struct pcb *)curproc->p_addr)->pcb_savefpu)) +#define SWD (*(struct swd *) &I387.swd) +#define ROUNDING ((I387.cwd >> 10) & 3) +#define PRECISION ((I387.cwd >> 8) & 3) + +#define BITS24 0 +#define BITS53 2 +#define BITS64 3 + +#define ROUND_NEAREST 0 +#define ROUND_DOWN 1 +#define ROUND_UP 2 +#define ROUND_0 3 + +#define CONSTZ (temp_real_unaligned) {0x0000,0x0000,0x0000,0x0000,0x0000} +#define CONST1 (temp_real_unaligned) {0x0000,0x0000,0x0000,0x8000,0x3FFF} +#define CONSTPI (temp_real_unaligned) {0xC235,0x2168,0xDAA2,0xC90F,0x4000} +#define CONSTLN2 (temp_real_unaligned) {0x79AC,0xD1CF,0x17F7,0xB172,0x3FFE} +#define CONSTLG2 (temp_real_unaligned) {0xF799,0xFBCF,0x9A84,0x9A20,0x3FFD} +#define CONSTL2E (temp_real_unaligned) {0xF0BC,0x5C17,0x3B29,0xB8AA,0x3FFF} +#define CONSTL2T (temp_real_unaligned) {0x8AFE,0xCD1B,0x784B,0xD49A,0x4000} + +#define set_IE() (I387.swd |= 1) +#define set_DE() (I387.swd |= 2) +#define set_ZE() (I387.swd |= 4) +#define set_OE() (I387.swd |= 8) +#define set_UE() (I387.swd |= 16) +#define set_PE() (I387.swd |= 32) + +#define set_C0() (I387.swd |= 0x0100) +#define set_C1() (I387.swd |= 0x0200) +#define set_C2() (I387.swd |= 0x0400) +#define set_C3() (I387.swd |= 0x4000) + +/* ea.c */ + +char * ea(struct trapframe *, unsigned short); + +/* convert.c */ + +void frndint(const temp_real * __a, temp_real * __b); +void Fscale(const temp_real *, const temp_real *, temp_real *); +void short_to_temp(const short_real * __a, temp_real * __b); +void long_to_temp(const long_real * __a, temp_real * __b); +void temp_to_short(const temp_real * __a, short_real * __b); +void temp_to_long(const temp_real * __a, long_real * __b); +void real_to_int(const temp_real * __a, temp_int * __b); +void int_to_real(const temp_int * __a, temp_real * __b); + +/* get_put.c */ + +void get_short_real(temp_real *, struct trapframe *, unsigned short); +void get_long_real(temp_real *, struct trapframe *, unsigned short); +void get_temp_real(temp_real *, struct trapframe *, unsigned short); +void get_short_int(temp_real *, struct trapframe *, unsigned short); +void get_long_int(temp_real *, struct trapframe *, unsigned short); +void get_longlong_int(temp_real *, struct trapframe *, unsigned short); +void get_BCD(temp_real *, struct trapframe *, unsigned short); +void put_short_real(const temp_real *, struct trapframe *, unsigned short); +void put_long_real(const temp_real *, struct trapframe *, unsigned short); +void put_temp_real(const temp_real *, struct trapframe *, unsigned short); +void put_short_int(const temp_real *, struct trapframe *, unsigned short); +void put_long_int(const temp_real *, struct trapframe *, unsigned short); +void put_longlong_int(const temp_real *, struct trapframe *, unsigned short); +void put_BCD(const temp_real *, struct trapframe *, unsigned short); + +/* add.c */ + +void fadd(const temp_real *, const temp_real *, temp_real *); + +/* mul.c */ + +void fmul(const temp_real *, const temp_real *, temp_real *); + +/* div.c */ + +void fdiv(const temp_real *, const temp_real *, temp_real *); + +/* compare.c */ + +void fcom(const temp_real *, const temp_real *); +void fucom(const temp_real *, const temp_real *); +void ftst(const temp_real *); + +#endif diff --git a/sys/i386/i386/math_emulate.c b/sys/i386/i386/math_emulate.c new file mode 100644 index 000000000000..faf55a452110 --- /dev/null +++ b/sys/i386/i386/math_emulate.c @@ -0,0 +1,1487 @@ +/* [expediant "port" of linux 8087 emulator to 386BSD, with apologies -wfj] */ +/* + * linux/kernel/math/math_emulate.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * Limited emulation 27.12.91 - mostly loads/stores, which gcc wants + * even for soft-float, unless you use bruce evans' patches. The patches + * are great, but they have to be re-applied for every version, and the + * library is different for soft-float and 80387. So emulation is more + * practical, even though it's slower. + * + * 28.12.91 - loads/stores work, even BCD. I'll have to start thinking + * about add/sub/mul/div. Urgel. I should find some good source, but I'll + * just fake up something. + * + * 30.12.91 - add/sub/mul/div/com seem to work mostly. I should really + * test every possible combination. + */ + +/* + * This file is full of ugly macros etc: one problem was that gcc simply + * didn't want to make the structures as they should be: it has to try to + * align them. Sickening code, but at least I've hidden the ugly things + * in this one file: the other files don't need to know about these things. + * + * The other files also don't care about ST(x) etc - they just get addresses + * to 80-bit temporary reals, and do with them as they please. I wanted to + * hide most of the 387-specific things here. + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 2 00060 + * -------------------- ----- ---------------------- + * + * 19 Sep 92 Ishii Masahiro Fix 0x1fd instruction + * kym@bingsuns.cc.binghamton.edu Fix fscale + * 28 Nov 92 Poul-Henning Kamp Reduce kernel size if you have + * a 387 or 486 chip + */ + +#include "machine/cpu.h" +#include "machine/psl.h" +#include "machine/reg.h" + +#include "param.h" +#include "systm.h" +#include "proc.h" +#include "user.h" +#include "acct.h" +#include "kernel.h" +#include "signal.h" + +#define __ALIGNED_TEMP_REAL 1 +#include "i386/i386/math_emu.h" + +#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x)) +#define ST(x) (*__st((x))) +#define PST(x) ((const temp_real *) __st((x))) +#define math_abort(tfp, signo) tfp->tf_eip = oldeip; return (signo); + +/* + * We don't want these inlined - it gets too messy in the machine-code. + */ +static void fpop(void); +static void fpush(void); +static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b); +static temp_real_unaligned * __st(int i); + +unsigned char get_fs_byte(char *adr) { return(fubyte(adr)); } +unsigned short get_fs_word(unsigned short *adr) { return(fuword(adr)); } +unsigned long get_fs_long(unsigned long *adr) { return(fuword(adr)); } +put_fs_byte(unsigned char val, char *adr) { (void)subyte(adr,val); } +put_fs_word(unsigned short val, short *adr) { (void)susword(adr,val); } +put_fs_long(unsigned long val, unsigned long *adr) { (void)suword(adr,val); } + +math_emulate(struct trapframe * info) +{ +#if defined(i486) || defined(i387) + panic("math_emulate(), shouldn't happen with -Di486 or -Di387"); +} +#else + unsigned short code; + temp_real tmp; + char * address; + u_long oldeip; + + /* ever used fp? */ + if ((((struct pcb *)curproc->p_addr)->pcb_flags & FP_SOFTFP) == 0) { + ((struct pcb *)curproc->p_addr)->pcb_flags |= FP_SOFTFP; + I387.cwd = 0x037f; + I387.swd = 0x0000; + I387.twd = 0x0000; + } + + if (I387.cwd & I387.swd & 0x3f) + I387.swd |= 0x8000; + else + I387.swd &= 0x7fff; + oldeip = info->tf_eip; +/* 0x001f means user code space */ + if ((u_short)info->tf_cs != 0x001F) { + printf("math_emulate: %04x:%08x\n\r", (u_short)info->tf_cs, + oldeip); + panic("?Math emulation needed in kernel?"); + } + code = get_fs_word((unsigned short *) oldeip); + bswapw(code); + code &= 0x7ff; + I387.fip = oldeip; + *(unsigned short *) &I387.fcs = (u_short) info->tf_cs; + *(1+(unsigned short *) &I387.fcs) = code; + info->tf_eip += 2; + switch (code) { + case 0x1d0: /* fnop */ + return(0); + case 0x1d1: case 0x1d2: case 0x1d3: + case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: + math_abort(info,SIGILL); + case 0x1e0: + ST(0).exponent ^= 0x8000; + return(0); + case 0x1e1: + ST(0).exponent &= 0x7fff; + return(0); + case 0x1e2: case 0x1e3: + math_abort(info,SIGILL); + case 0x1e4: + ftst(PST(0)); + return(0); + case 0x1e5: + printf("fxam not implemented\n\r"); + math_abort(info,SIGILL); + case 0x1e6: case 0x1e7: + math_abort(info,SIGILL); + case 0x1e8: + fpush(); + ST(0) = CONST1; + return(0); + case 0x1e9: + fpush(); + ST(0) = CONSTL2T; + return(0); + case 0x1ea: + fpush(); + ST(0) = CONSTL2E; + return(0); + case 0x1eb: + fpush(); + ST(0) = CONSTPI; + return(0); + case 0x1ec: + fpush(); + ST(0) = CONSTLG2; + return(0); + case 0x1ed: + fpush(); + ST(0) = CONSTLN2; + return(0); + case 0x1ee: + fpush(); + ST(0) = CONSTZ; + return(0); + case 0x1ef: + math_abort(info,SIGILL); + case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3: + case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7: + case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb: + case 0x1fe: case 0x1ff: + uprintf( + "math_emulate: instruction %04x not implemented\n", + code + 0xd800); + math_abort(info,SIGILL); + case 0x1fd: + /* incomplete and totally inadequate -wfj */ + Fscale(PST(0), PST(1), &tmp); + real_to_real(&tmp,&ST(0)); + return(0); /* 19 Sep 92*/ + case 0x1fc: + frndint(PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 0x2e9: + fucom(PST(1),PST(0)); + fpop(); fpop(); + return(0); + case 0x3d0: case 0x3d1: + return(0); + case 0x3e2: + I387.swd &= 0x7f00; + return(0); + case 0x3e3: + I387.cwd = 0x037f; + I387.swd = 0x0000; + I387.twd = 0x0000; + return(0); + case 0x3e4: + return(0); + case 0x6d9: + fcom(PST(1),PST(0)); + fpop(); fpop(); + return(0); + case 0x7e0: + *(short *) &info->tf_eax = I387.swd; + return(0); + } + switch (code >> 3) { + case 0x18: + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 0x19: + fmul(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 0x1a: + fcom(PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 0x1b: + fcom(PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + fpop(); + return(0); + case 0x1c: + real_to_real(&ST(code & 7),&tmp); + tmp.exponent ^= 0x8000; + fadd(PST(0),&tmp,&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 0x1d: + ST(0).exponent ^= 0x8000; + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 0x1e: + fdiv(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 0x1f: + fdiv(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 0x38: + fpush(); + ST(0) = ST((code & 7)+1); + return(0); + case 0x39: + fxchg(&ST(0),&ST(code & 7)); + return(0); + case 0x3b: + ST(code & 7) = ST(0); + fpop(); + return(0); + case 0x98: + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return(0); + case 0x99: + fmul(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return(0); + case 0x9a: + fcom(PST(code & 7),PST(0)); + return(0); + case 0x9b: + fcom(PST(code & 7),PST(0)); + fpop(); + return(0); + case 0x9c: + ST(code & 7).exponent ^= 0x8000; + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return(0); + case 0x9d: + real_to_real(&ST(0),&tmp); + tmp.exponent ^= 0x8000; + fadd(PST(code & 7),&tmp,&tmp); + real_to_real(&tmp,&ST(code & 7)); + return(0); + case 0x9e: + fdiv(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return(0); + case 0x9f: + fdiv(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(code & 7)); + return(0); + case 0xb8: + printf("ffree not implemented\n\r"); + math_abort(info,SIGILL); + case 0xb9: + fxchg(&ST(0),&ST(code & 7)); + return(0); + case 0xba: + ST(code & 7) = ST(0); + return(0); + case 0xbb: + ST(code & 7) = ST(0); + fpop(); + return(0); + case 0xbc: + fucom(PST(code & 7),PST(0)); + return(0); + case 0xbd: + fucom(PST(code & 7),PST(0)); + fpop(); + return(0); + case 0xd8: + fadd(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return(0); + case 0xd9: + fmul(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return(0); + case 0xda: + fcom(PST(code & 7),PST(0)); + fpop(); + return(0); + case 0xdc: + ST(code & 7).exponent ^= 0x8000; + fadd(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return(0); + case 0xdd: + real_to_real(&ST(0),&tmp); + tmp.exponent ^= 0x8000; + fadd(PST(code & 7),&tmp,&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return(0); + case 0xde: + fdiv(PST(0),PST(code & 7),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return(0); + case 0xdf: + fdiv(PST(code & 7),PST(0),&tmp); + real_to_real(&tmp,&ST(code & 7)); + fpop(); + return(0); + case 0xf8: + printf("ffree not implemented\n\r"); + math_abort(info,SIGILL); + fpop(); + return(0); + case 0xf9: + fxchg(&ST(0),&ST(code & 7)); + return(0); + case 0xfa: + case 0xfb: + ST(code & 7) = ST(0); + fpop(); + return(0); + } + switch ((code>>3) & 0xe7) { + case 0x22: + put_short_real(PST(0),info,code); + return(0); + case 0x23: + put_short_real(PST(0),info,code); + fpop(); + return(0); + case 0x24: + address = ea(info,code); + for (code = 0 ; code < 7 ; code++) { + ((long *) & I387)[code] = + get_fs_long((unsigned long *) address); + address += 4; + } + return(0); + case 0x25: + address = ea(info,code); + *(unsigned short *) &I387.cwd = + get_fs_word((unsigned short *) address); + return(0); + case 0x26: + address = ea(info,code); + /*verify_area(address,28);*/ + for (code = 0 ; code < 7 ; code++) { + put_fs_long( ((long *) & I387)[code], + (unsigned long *) address); + address += 4; + } + return(0); + case 0x27: + address = ea(info,code); + /*verify_area(address,2);*/ + put_fs_word(I387.cwd,(short *) address); + return(0); + case 0x62: + put_long_int(PST(0),info,code); + return(0); + case 0x63: + put_long_int(PST(0),info,code); + fpop(); + return(0); + case 0x65: + fpush(); + get_temp_real(&tmp,info,code); + real_to_real(&tmp,&ST(0)); + return(0); + case 0x67: + put_temp_real(PST(0),info,code); + fpop(); + return(0); + case 0xa2: + put_long_real(PST(0),info,code); + return(0); + case 0xa3: + put_long_real(PST(0),info,code); + fpop(); + return(0); + case 0xa4: + address = ea(info,code); + for (code = 0 ; code < 27 ; code++) { + ((long *) & I387)[code] = + get_fs_long((unsigned long *) address); + address += 4; + } + return(0); + case 0xa6: + address = ea(info,code); + /*verify_area(address,108);*/ + for (code = 0 ; code < 27 ; code++) { + put_fs_long( ((long *) & I387)[code], + (unsigned long *) address); + address += 4; + } + I387.cwd = 0x037f; + I387.swd = 0x0000; + I387.twd = 0x0000; + return(0); + case 0xa7: + address = ea(info,code); + /*verify_area(address,2);*/ + put_fs_word(I387.swd,(short *) address); + return(0); + case 0xe2: + put_short_int(PST(0),info,code); + return(0); + case 0xe3: + put_short_int(PST(0),info,code); + fpop(); + return(0); + case 0xe4: + fpush(); + get_BCD(&tmp,info,code); + real_to_real(&tmp,&ST(0)); + return(0); + case 0xe5: + fpush(); + get_longlong_int(&tmp,info,code); + real_to_real(&tmp,&ST(0)); + return(0); + case 0xe6: + put_BCD(PST(0),info,code); + fpop(); + return(0); + case 0xe7: + put_longlong_int(PST(0),info,code); + fpop(); + return(0); + } + switch (code >> 9) { + case 0: + get_short_real(&tmp,info,code); + break; + case 1: + get_long_int(&tmp,info,code); + break; + case 2: + get_long_real(&tmp,info,code); + break; + case 4: + get_short_int(&tmp,info,code); + } + switch ((code>>3) & 0x27) { + case 0: + fadd(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 1: + fmul(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 2: + fcom(&tmp,PST(0)); + return(0); + case 3: + fcom(&tmp,PST(0)); + fpop(); + return(0); + case 4: + tmp.exponent ^= 0x8000; + fadd(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 5: + ST(0).exponent ^= 0x8000; + fadd(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 6: + fdiv(PST(0),&tmp,&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + case 7: + fdiv(&tmp,PST(0),&tmp); + real_to_real(&tmp,&ST(0)); + return(0); + } + if ((code & 0x138) == 0x100) { + fpush(); + real_to_real(&tmp,&ST(0)); + return(0); + } + printf("Unknown math-insns: %04x:%08x %04x\n\r",(u_short)info->tf_cs, + info->tf_eip,code); + math_abort(info,SIGFPE); +} + +static void fpop(void) +{ + unsigned long tmp; + + tmp = I387.swd & 0xffffc7ff; + I387.swd += 0x00000800; + I387.swd &= 0x00003800; + I387.swd |= tmp; +} + +static void fpush(void) +{ + unsigned long tmp; + + tmp = I387.swd & 0xffffc7ff; + I387.swd += 0x00003800; + I387.swd &= 0x00003800; + I387.swd |= tmp; +} + +static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b) +{ + temp_real_unaligned c; + + c = *a; + *a = *b; + *b = c; +} + +static temp_real_unaligned * __st(int i) +{ + i += I387.swd >> 11; + i &= 7; + return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space)); +} + +/* + * linux/kernel/math/ea.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * Calculate the effective address. + */ + + +static int __regoffset[] = { + tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI +}; + +#define REG(x) (curproc->p_regs[__regoffset[(x)]]) + +static char * sib(struct trapframe * info, int mod) +{ + unsigned char ss,index,base; + long offset = 0; + + base = get_fs_byte((char *) info->tf_eip); + info->tf_eip++; + ss = base >> 6; + index = (base >> 3) & 7; + base &= 7; + if (index == 4) + offset = 0; + else + offset = REG(index); + offset <<= ss; + if (mod || base != 5) + offset += REG(base); + if (mod == 1) { + offset += (signed char) get_fs_byte((char *) info->tf_eip); + info->tf_eip++; + } else if (mod == 2 || base == 5) { + offset += (signed) get_fs_long((unsigned long *) info->tf_eip); + info->tf_eip += 4; + } + I387.foo = offset; + I387.fos = 0x17; + return (char *) offset; +} + +char * ea(struct trapframe * info, unsigned short code) +{ + unsigned char mod,rm; + long * tmp; + int offset = 0; + + mod = (code >> 6) & 3; + rm = code & 7; + if (rm == 4 && mod != 3) + return sib(info,mod); + if (rm == 5 && !mod) { + offset = get_fs_long((unsigned long *) info->tf_eip); + info->tf_eip += 4; + I387.foo = offset; + I387.fos = 0x17; + return (char *) offset; + } + tmp = & (long)REG(rm); + switch (mod) { + case 0: offset = 0; break; + case 1: + offset = (signed char) get_fs_byte((char *) info->tf_eip); + info->tf_eip++; + break; + case 2: + offset = (signed) get_fs_long((unsigned long *) info->tf_eip); + info->tf_eip += 4; + break; +#ifdef notyet + case 3: + math_abort(info,1<<(SIGILL-1)); +#endif + } + I387.foo = offset; + I387.fos = 0x17; + return offset + (char *) *tmp; +} +/* + * linux/kernel/math/get_put.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * This file handles all accesses to user memory: getting and putting + * ints/reals/BCD etc. This is the only part that concerns itself with + * other than temporary real format. All other cals are strictly temp_real. + */ + +void get_short_real(temp_real * tmp, + struct trapframe * info, unsigned short code) +{ + char * addr; + short_real sr; + + addr = ea(info,code); + sr = get_fs_long((unsigned long *) addr); + short_to_temp(&sr,tmp); +} + +void get_long_real(temp_real * tmp, + struct trapframe * info, unsigned short code) +{ + char * addr; + long_real lr; + + addr = ea(info,code); + lr.a = get_fs_long((unsigned long *) addr); + lr.b = get_fs_long(1 + (unsigned long *) addr); + long_to_temp(&lr,tmp); +} + +void get_temp_real(temp_real * tmp, + struct trapframe * info, unsigned short code) +{ + char * addr; + + addr = ea(info,code); + tmp->a = get_fs_long((unsigned long *) addr); + tmp->b = get_fs_long(1 + (unsigned long *) addr); + tmp->exponent = get_fs_word(4 + (unsigned short *) addr); +} + +void get_short_int(temp_real * tmp, + struct trapframe * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + ti.a = (signed short) get_fs_word((unsigned short *) addr); + ti.b = 0; + if (ti.sign = (ti.a < 0)) + ti.a = - ti.a; + int_to_real(&ti,tmp); +} + +void get_long_int(temp_real * tmp, + struct trapframe * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + ti.a = get_fs_long((unsigned long *) addr); + ti.b = 0; + if (ti.sign = (ti.a < 0)) + ti.a = - ti.a; + int_to_real(&ti,tmp); +} + +void get_longlong_int(temp_real * tmp, + struct trapframe * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + ti.a = get_fs_long((unsigned long *) addr); + ti.b = get_fs_long(1 + (unsigned long *) addr); + if (ti.sign = (ti.b < 0)) + __asm__("notl %0 ; notl %1\n\t" + "addl $1,%0 ; adcl $0,%1" + :"=r" (ti.a),"=r" (ti.b) + :"0" (ti.a),"1" (ti.b)); + int_to_real(&ti,tmp); +} + +#define MUL10(low,high) \ +__asm__("addl %0,%0 ; adcl %1,%1\n\t" \ +"movl %0,%%ecx ; movl %1,%%ebx\n\t" \ +"addl %0,%0 ; adcl %1,%1\n\t" \ +"addl %0,%0 ; adcl %1,%1\n\t" \ +"addl %%ecx,%0 ; adcl %%ebx,%1" \ +:"=a" (low),"=d" (high) \ +:"0" (low),"1" (high):"cx","bx") + +#define ADD64(val,low,high) \ +__asm__("addl %4,%0 ; adcl $0,%1":"=r" (low),"=r" (high) \ +:"0" (low),"1" (high),"r" ((unsigned long) (val))) + +void get_BCD(temp_real * tmp, struct trapframe * info, unsigned short code) +{ + int k; + char * addr; + temp_int i; + unsigned char c; + + addr = ea(info,code); + addr += 9; + i.sign = 0x80 & get_fs_byte(addr--); + i.a = i.b = 0; + for (k = 0; k < 9; k++) { + c = get_fs_byte(addr--); + MUL10(i.a, i.b); + ADD64((c>>4), i.a, i.b); + MUL10(i.a, i.b); + ADD64((c&0xf), i.a, i.b); + } + int_to_real(&i,tmp); +} + +void put_short_real(const temp_real * tmp, + struct trapframe * info, unsigned short code) +{ + char * addr; + short_real sr; + + addr = ea(info,code); + /*verify_area(addr,4);*/ + temp_to_short(tmp,&sr); + put_fs_long(sr,(unsigned long *) addr); +} + +void put_long_real(const temp_real * tmp, + struct trapframe * info, unsigned short code) +{ + char * addr; + long_real lr; + + addr = ea(info,code); + /*verify_area(addr,8);*/ + temp_to_long(tmp,&lr); + put_fs_long(lr.a, (unsigned long *) addr); + put_fs_long(lr.b, 1 + (unsigned long *) addr); +} + +void put_temp_real(const temp_real * tmp, + struct trapframe * info, unsigned short code) +{ + char * addr; + + addr = ea(info,code); + /*verify_area(addr,10);*/ + put_fs_long(tmp->a, (unsigned long *) addr); + put_fs_long(tmp->b, 1 + (unsigned long *) addr); + put_fs_word(tmp->exponent, 4 + (short *) addr); +} + +void put_short_int(const temp_real * tmp, + struct trapframe * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + real_to_int(tmp,&ti); + /*verify_area(addr,2);*/ + if (ti.sign) + ti.a = -ti.a; + put_fs_word(ti.a,(short *) addr); +} + +void put_long_int(const temp_real * tmp, + struct trapframe * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + real_to_int(tmp,&ti); + /*verify_area(addr,4);*/ + if (ti.sign) + ti.a = -ti.a; + put_fs_long(ti.a,(unsigned long *) addr); +} + +void put_longlong_int(const temp_real * tmp, + struct trapframe * info, unsigned short code) +{ + char * addr; + temp_int ti; + + addr = ea(info,code); + real_to_int(tmp,&ti); + /*verify_area(addr,8);*/ + if (ti.sign) + __asm__("notl %0 ; notl %1\n\t" + "addl $1,%0 ; adcl $0,%1" + :"=r" (ti.a),"=r" (ti.b) + :"0" (ti.a),"1" (ti.b)); + put_fs_long(ti.a,(unsigned long *) addr); + put_fs_long(ti.b,1 + (unsigned long *) addr); +} + +#define DIV10(low,high,rem) \ +__asm__("divl %6 ; xchgl %1,%2 ; divl %6" \ + :"=d" (rem),"=a" (low),"=r" (high) \ + :"0" (0),"1" (high),"2" (low),"c" (10)) + +void put_BCD(const temp_real * tmp,struct trapframe * info, unsigned short code) +{ + int k,rem; + char * addr; + temp_int i; + unsigned char c; + + addr = ea(info,code); + /*verify_area(addr,10);*/ + real_to_int(tmp,&i); + if (i.sign) + put_fs_byte(0x80, addr+9); + else + put_fs_byte(0, addr+9); + for (k = 0; k < 9; k++) { + DIV10(i.a,i.b,rem); + c = rem; + DIV10(i.a,i.b,rem); + c += rem<<4; + put_fs_byte(c,addr++); + } +} + +/* + * linux/kernel/math/mul.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * temporary real multiplication routine. + */ + + +static void shift(int * c) +{ + __asm__("movl (%0),%%eax ; addl %%eax,(%0)\n\t" + "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t" + "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t" + "movl 12(%0),%%eax ; adcl %%eax,12(%0)" + ::"r" ((long) c):"ax"); +} + +static void mul64(const temp_real * a, const temp_real * b, int * c) +{ + __asm__("movl (%0),%%eax\n\t" + "mull (%1)\n\t" + "movl %%eax,(%2)\n\t" + "movl %%edx,4(%2)\n\t" + "movl 4(%0),%%eax\n\t" + "mull 4(%1)\n\t" + "movl %%eax,8(%2)\n\t" + "movl %%edx,12(%2)\n\t" + "movl (%0),%%eax\n\t" + "mull 4(%1)\n\t" + "addl %%eax,4(%2)\n\t" + "adcl %%edx,8(%2)\n\t" + "adcl $0,12(%2)\n\t" + "movl 4(%0),%%eax\n\t" + "mull (%1)\n\t" + "addl %%eax,4(%2)\n\t" + "adcl %%edx,8(%2)\n\t" + "adcl $0,12(%2)" + ::"S" ((long) a),"c" ((long) b),"D" ((long) c) + :"ax","dx"); +} + +void fmul(const temp_real * src1, const temp_real * src2, temp_real * result) +{ + int i,sign; + int tmp[4] = {0,0,0,0}; + + sign = (src1->exponent ^ src2->exponent) & 0x8000; + i = (src1->exponent & 0x7fff) + (src2->exponent & 0x7fff) - 16383 + 1; + if (i<0) { + result->exponent = sign; + result->a = result->b = 0; + return; + } + if (i>0x7fff) { + set_OE(); + return; + } + mul64(src1,src2,tmp); + if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) + while (i && tmp[3] >= 0) { + i--; + shift(tmp); + } + else + i = 0; + result->exponent = i | sign; + result->a = tmp[2]; + result->b = tmp[3]; +} + +/* + * linux/kernel/math/div.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * temporary real division routine. + */ + +#include "i386/i386/math_emu.h" + +static void shift_left(int * c) +{ + __asm__ __volatile__("movl (%0),%%eax ; addl %%eax,(%0)\n\t" + "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t" + "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t" + "movl 12(%0),%%eax ; adcl %%eax,12(%0)" + ::"r" ((long) c):"ax"); +} + +static void shift_right(int * c) +{ + __asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)" + ::"r" ((long) c)); +} + +static int try_sub(int * a, int * b) +{ + char ok; + + __asm__ __volatile__("movl (%1),%%eax ; subl %%eax,(%2)\n\t" + "movl 4(%1),%%eax ; sbbl %%eax,4(%2)\n\t" + "movl 8(%1),%%eax ; sbbl %%eax,8(%2)\n\t" + "movl 12(%1),%%eax ; sbbl %%eax,12(%2)\n\t" + "setae %%al":"=a" (ok):"c" ((long) a),"d" ((long) b)); + return ok; +} + +static void div64(int * a, int * b, int * c) +{ + int tmp[4]; + int i; + unsigned int mask = 0; + + c += 4; + for (i = 0 ; i<64 ; i++) { + if (!(mask >>= 1)) { + c--; + mask = 0x80000000; + } + tmp[0] = a[0]; tmp[1] = a[1]; + tmp[2] = a[2]; tmp[3] = a[3]; + if (try_sub(b,tmp)) { + *c |= mask; + a[0] = tmp[0]; a[1] = tmp[1]; + a[2] = tmp[2]; a[3] = tmp[3]; + } + shift_right(b); + } +} + +void fdiv(const temp_real * src1, const temp_real * src2, temp_real * result) +{ + int i,sign; + int a[4],b[4],tmp[4] = {0,0,0,0}; + + sign = (src1->exponent ^ src2->exponent) & 0x8000; + if (!(src2->a || src2->b)) { + set_ZE(); + return; + } + i = (src1->exponent & 0x7fff) - (src2->exponent & 0x7fff) + 16383; + if (i<0) { + set_UE(); + result->exponent = sign; + result->a = result->b = 0; + return; + } + a[0] = a[1] = 0; + a[2] = src1->a; + a[3] = src1->b; + b[0] = b[1] = 0; + b[2] = src2->a; + b[3] = src2->b; + while (b[3] >= 0) { + i++; + shift_left(b); + } + div64(a,b,tmp); + if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) { + while (i && tmp[3] >= 0) { + i--; + shift_left(tmp); + } + if (tmp[3] >= 0) + set_DE(); + } else + i = 0; + if (i>0x7fff) { + set_OE(); + return; + } + if (tmp[0] || tmp[1]) + set_PE(); + result->exponent = i | sign; + result->a = tmp[2]; + result->b = tmp[3]; +} + +/* + * linux/kernel/math/add.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * temporary real addition routine. + * + * NOTE! These aren't exact: they are only 62 bits wide, and don't do + * correct rounding. Fast hack. The reason is that we shift right the + * values by two, in order not to have overflow (1 bit), and to be able + * to move the sign into the mantissa (1 bit). Much simpler algorithms, + * and 62 bits (61 really - no rounding) accuracy is usually enough. The + * only time you should notice anything weird is when adding 64-bit + * integers together. When using doubles (52 bits accuracy), the + * 61-bit accuracy never shows at all. + */ + +#define NEGINT(a) \ +__asm__("notl %0 ; notl %1 ; addl $1,%0 ; adcl $0,%1" \ + :"=r" (a->a),"=r" (a->b) \ + :"0" (a->a),"1" (a->b)) + +static void signify(temp_real * a) +{ + a->exponent += 2; + __asm__("shrdl $2,%1,%0 ; shrl $2,%1" + :"=r" (a->a),"=r" (a->b) + :"0" (a->a),"1" (a->b)); + if (a->exponent < 0) + NEGINT(a); + a->exponent &= 0x7fff; +} + +static void unsignify(temp_real * a) +{ + if (!(a->a || a->b)) { + a->exponent = 0; + return; + } + a->exponent &= 0x7fff; + if (a->b < 0) { + NEGINT(a); + a->exponent |= 0x8000; + } + while (a->b >= 0) { + a->exponent--; + __asm__("addl %0,%0 ; adcl %1,%1" + :"=r" (a->a),"=r" (a->b) + :"0" (a->a),"1" (a->b)); + } +} + +void fadd(const temp_real * src1, const temp_real * src2, temp_real * result) +{ + temp_real a,b; + int x1,x2,shift; + + x1 = src1->exponent & 0x7fff; + x2 = src2->exponent & 0x7fff; + if (x1 > x2) { + a = *src1; + b = *src2; + shift = x1-x2; + } else { + a = *src2; + b = *src1; + shift = x2-x1; + } + if (shift >= 64) { + *result = a; + return; + } + if (shift >= 32) { + b.a = b.b; + b.b = 0; + shift -= 32; + } + __asm__("shrdl %4,%1,%0 ; shrl %4,%1" + :"=r" (b.a),"=r" (b.b) + :"0" (b.a),"1" (b.b),"c" ((char) shift)); + signify(&a); + signify(&b); + __asm__("addl %4,%0 ; adcl %5,%1" + :"=r" (a.a),"=r" (a.b) + :"0" (a.a),"1" (a.b),"g" (b.a),"g" (b.b)); + unsignify(&a); + *result = a; +} + +/* + * linux/kernel/math/compare.c + * + * (C) 1991 Linus Torvalds + */ + +/* + * temporary real comparison routines + */ + + +#define clear_Cx() (I387.swd &= ~0x4500) + +static void normalize(temp_real * a) +{ + int i = a->exponent & 0x7fff; + int sign = a->exponent & 0x8000; + + if (!(a->a || a->b)) { + a->exponent = 0; + return; + } + while (i && a->b >= 0) { + i--; + __asm__("addl %0,%0 ; adcl %1,%1" + :"=r" (a->a),"=r" (a->b) + :"0" (a->a),"1" (a->b)); + } + a->exponent = i | sign; +} + +void ftst(const temp_real * a) +{ + temp_real b; + + clear_Cx(); + b = *a; + normalize(&b); + if (b.a || b.b || b.exponent) { + if (b.exponent < 0) + set_C0(); + } else + set_C3(); +} + +void fcom(const temp_real * src1, const temp_real * src2) +{ + temp_real a; + + a = *src1; + a.exponent ^= 0x8000; + fadd(&a,src2,&a); + ftst(&a); +} + +void fucom(const temp_real * src1, const temp_real * src2) +{ + fcom(src1,src2); +} + +/* + * linux/kernel/math/convert.c + * + * (C) 1991 Linus Torvalds + */ + + +/* + * NOTE!!! There is some "non-obvious" optimisations in the temp_to_long + * and temp_to_short conversion routines: don't touch them if you don't + * know what's going on. They are the adding of one in the rounding: the + * overflow bit is also used for adding one into the exponent. Thus it + * looks like the overflow would be incorrectly handled, but due to the + * way the IEEE numbers work, things are correct. + * + * There is no checking for total overflow in the conversions, though (ie + * if the temp-real number simply won't fit in a short- or long-real.) + */ + +void short_to_temp(const short_real * a, temp_real * b) +{ + if (!(*a & 0x7fffffff)) { + b->a = b->b = 0; + if (*a) + b->exponent = 0x8000; + else + b->exponent = 0; + return; + } + b->exponent = ((*a>>23) & 0xff)-127+16383; + if (*a<0) + b->exponent |= 0x8000; + b->b = (*a<<8) | 0x80000000; + b->a = 0; +} + +void long_to_temp(const long_real * a, temp_real * b) +{ + if (!a->a && !(a->b & 0x7fffffff)) { + b->a = b->b = 0; + if (a->b) + b->exponent = 0x8000; + else + b->exponent = 0; + return; + } + b->exponent = ((a->b >> 20) & 0x7ff)-1023+16383; + if (a->b<0) + b->exponent |= 0x8000; + b->b = 0x80000000 | (a->b<<11) | (((unsigned long)a->a)>>21); + b->a = a->a<<11; +} + +void temp_to_short(const temp_real * a, short_real * b) +{ + if (!(a->exponent & 0x7fff)) { + *b = (a->exponent)?0x80000000:0; + return; + } + *b = ((((long) a->exponent)-16383+127) << 23) & 0x7f800000; + if (a->exponent < 0) + *b |= 0x80000000; + *b |= (a->b >> 8) & 0x007fffff; + switch (ROUNDING) { + case ROUND_NEAREST: + if ((a->b & 0xff) > 0x80) + ++*b; + break; + case ROUND_DOWN: + if ((a->exponent & 0x8000) && (a->b & 0xff)) + ++*b; + break; + case ROUND_UP: + if (!(a->exponent & 0x8000) && (a->b & 0xff)) + ++*b; + break; + } +} + +void temp_to_long(const temp_real * a, long_real * b) +{ + if (!(a->exponent & 0x7fff)) { + b->a = 0; + b->b = (a->exponent)?0x80000000:0; + return; + } + b->b = (((0x7fff & (long) a->exponent)-16383+1023) << 20) & 0x7ff00000; + if (a->exponent < 0) + b->b |= 0x80000000; + b->b |= (a->b >> 11) & 0x000fffff; + b->a = a->b << 21; + b->a |= (a->a >> 11) & 0x001fffff; + switch (ROUNDING) { + case ROUND_NEAREST: + if ((a->a & 0x7ff) > 0x400) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + case ROUND_DOWN: + if ((a->exponent & 0x8000) && (a->b & 0xff)) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + case ROUND_UP: + if (!(a->exponent & 0x8000) && (a->b & 0xff)) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + } +} + +void frndint(const temp_real * a, temp_real * b) +{ + int shift = 16383 + 63 - (a->exponent & 0x7fff); + unsigned long underflow; + + if ((shift < 0) || (shift == 16383+63)) { + *b = *a; + return; + } + b->a = b->b = underflow = 0; + b->exponent = a->exponent; + if (shift < 32) { + b->b = a->b; b->a = a->a; + } else if (shift < 64) { + b->a = a->b; underflow = a->a; + shift -= 32; + b->exponent += 32; + } else if (shift < 96) { + underflow = a->b; + shift -= 64; + b->exponent += 64; + } else { + underflow = 1; + shift = 0; + } + b->exponent += shift; + __asm__("shrdl %2,%1,%0" + :"=r" (underflow),"=r" (b->a) + :"c" ((char) shift),"0" (underflow),"1" (b->a)); + __asm__("shrdl %2,%1,%0" + :"=r" (b->a),"=r" (b->b) + :"c" ((char) shift),"0" (b->a),"1" (b->b)); + __asm__("shrl %1,%0" + :"=r" (b->b) + :"c" ((char) shift),"0" (b->b)); + switch (ROUNDING) { + case ROUND_NEAREST: + __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b) + ,"r" (0x7fffffff + (b->a & 1)) + ,"m" (*&underflow)); + break; + case ROUND_UP: + if ((b->exponent >= 0) && underflow) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + case ROUND_DOWN: + if ((b->exponent < 0) && underflow) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + } + if (b->a || b->b) + while (b->b >= 0) { + b->exponent--; + __asm__("addl %0,%0 ; adcl %1,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + } + else + b->exponent = 0; +} + +void Fscale(const temp_real *a, const temp_real *b, temp_real *c) +{ + temp_int ti; + + *c = *a; + if(!c->a && !c->b) { /* 19 Sep 92*/ + c->exponent = 0; + return; + } + real_to_int(b, &ti); + if(ti.sign) + c->exponent -= ti.a; + else + c->exponent += ti.a; +} + +void real_to_int(const temp_real * a, temp_int * b) +{ + int shift = 16383 + 63 - (a->exponent & 0x7fff); + unsigned long underflow; + + b->a = b->b = underflow = 0; + b->sign = (a->exponent < 0); + if (shift < 0) { + set_OE(); + return; + } + if (shift < 32) { + b->b = a->b; b->a = a->a; + } else if (shift < 64) { + b->a = a->b; underflow = a->a; + shift -= 32; + } else if (shift < 96) { + underflow = a->b; + shift -= 64; + } else { + underflow = 1; + shift = 0; + } + __asm__("shrdl %2,%1,%0" + :"=r" (underflow),"=r" (b->a) + :"c" ((char) shift),"0" (underflow),"1" (b->a)); + __asm__("shrdl %2,%1,%0" + :"=r" (b->a),"=r" (b->b) + :"c" ((char) shift),"0" (b->a),"1" (b->b)); + __asm__("shrl %1,%0" + :"=r" (b->b) + :"c" ((char) shift),"0" (b->b)); + switch (ROUNDING) { + case ROUND_NEAREST: + __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b) + ,"r" (0x7fffffff + (b->a & 1)) + ,"m" (*&underflow)); + break; + case ROUND_UP: + if (!b->sign && underflow) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + case ROUND_DOWN: + if (b->sign && underflow) + __asm__("addl $1,%0 ; adcl $0,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + break; + } +} + +void int_to_real(const temp_int * a, temp_real * b) +{ + b->a = a->a; + b->b = a->b; + if (b->a || b->b) + b->exponent = 16383 + 63 + (a->sign? 0x8000:0); + else { + b->exponent = 0; + return; + } + while (b->b >= 0) { + b->exponent--; + __asm__("addl %0,%0 ; adcl %1,%1" + :"=r" (b->a),"=r" (b->b) + :"0" (b->a),"1" (b->b)); + } +} +#endif /* defined(i486) || defined(i387) */ diff --git a/sys/i386/i386/mem.c b/sys/i386/i386/mem.c new file mode 100644 index 000000000000..650e21eb509c --- /dev/null +++ b/sys/i386/i386/mem.c @@ -0,0 +1,191 @@ +/*- + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1986, 1990 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 code 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. + * + * from: Utah $Hdr: mem.c 1.13 89/10/08$ + * @(#)mem.c 7.2 (Berkeley) 5/9/91 + */ + +/* + * Memory special file + */ + +#include "param.h" +#include "conf.h" +#include "buf.h" +#include "systm.h" +#include "uio.h" +#include "malloc.h" + +#include "machine/cpu.h" + +#include "vm/vm_param.h" +#include "vm/lock.h" +#include "vm/vm_statistics.h" +#include "vm/pmap.h" +#include "vm/vm_prot.h" + +extern char *vmmap; /* poor name! */ +/*ARGSUSED*/ +mmrw(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + register int o; + register u_int c, v; + register struct iovec *iov; + int error = 0; + caddr_t zbuf = NULL; + + 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; + pmap_enter(pmap_kernel(), vmmap, v, + uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE, + TRUE); + o = (int)uio->uio_offset & PGOFSET; + c = (u_int)(NBPG - ((int)iov->iov_base & PGOFSET)); + c = MIN(c, (u_int)(NBPG - o)); + c = MIN(c, (u_int)iov->iov_len); + error = uiomove((caddr_t)&vmmap[o], (int)c, uio); + pmap_remove(pmap_kernel(), vmmap, &vmmap[NBPG]); + continue; + +/* minor device 1 is kernel memory */ + case 1: + c = iov->iov_len; + if (!kernacc((caddr_t)uio->uio_offset, c, + uio->uio_rw == UIO_READ ? B_READ : B_WRITE)) + return(EFAULT); + error = uiomove((caddr_t)uio->uio_offset, (int)c, uio); + continue; + +/* minor device 2 is EOF/RATHOLE */ + case 2: + if (uio->uio_rw == UIO_READ) + return (0); + c = iov->iov_len; + break; + +/* 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 (zbuf == NULL) { + zbuf = (caddr_t) + malloc(CLBYTES, M_TEMP, M_WAITOK); + bzero(zbuf, CLBYTES); + } + c = MIN(iov->iov_len, CLBYTES); + error = uiomove(zbuf, (int)c, uio); + continue; + +#ifdef notyet +/* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate + i/o device address bus, different than memory bus. Semantics here are + very different than ordinary read/write, as if iov_len is a multiple + an implied string move from a single port will be done. Note that lseek + must be used to set the port number reliably. */ + case 14: + if (iov->iov_len == 1) { + u_char tmp; + tmp = inb(uio->uio_offset); + error = uiomove (&tmp, iov->iov_len, uio); + } else { + if (!useracc((caddr_t)iov->iov_base, + iov->iov_len, uio->uio_rw)) + return (EFAULT); + insb(uio->uio_offset, iov->iov_base, + iov->iov_len); + } + break; + case 15: + if (iov->iov_len == sizeof (short)) { + u_short tmp; + tmp = inw(uio->uio_offset); + error = uiomove (&tmp, iov->iov_len, uio); + } else { + if (!useracc((caddr_t)iov->iov_base, + iov->iov_len, uio->uio_rw)) + return (EFAULT); + insw(uio->uio_offset, iov->iov_base, + iov->iov_len/ sizeof (short)); + } + break; + case 16: + if (iov->iov_len == sizeof (long)) { + u_long tmp; + tmp = inl(uio->uio_offset); + error = uiomove (&tmp, iov->iov_len, uio); + } else { + if (!useracc((caddr_t)iov->iov_base, + iov->iov_len, uio->uio_rw)) + return (EFAULT); + insl(uio->uio_offset, iov->iov_base, + iov->iov_len/ sizeof (long)); + } + break; +#endif + + default: + return (ENXIO); + } + if (error) + break; + iov->iov_base += c; + iov->iov_len -= c; + uio->uio_offset += c; + uio->uio_resid -= c; + } + if (zbuf) + free(zbuf, M_TEMP); + return (error); +} diff --git a/sys/i386/i386/microtime.s b/sys/i386/i386/microtime.s new file mode 100644 index 000000000000..4af938b9179a --- /dev/null +++ b/sys/i386/i386/microtime.s @@ -0,0 +1,135 @@ +/*- + * 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. + * + * $Header$ + */ + +#include "asm.h" +#include "../isa/isa.h" +#include "../isa/timerreg.h" + +/* + * Use a higher resolution version of microtime if HZ is not + * overridden (i.e. it is 100Hz). + */ +#ifndef HZ +ENTRY(microtime) + pushl %edi + pushl %esi + pushl %ebx + + movl $_time,%ebx + + cli # disable interrupts + + movl (%ebx),%edi # sec = time.tv_sec + movl 4(%ebx),%esi # usec = time.tv_usec + + movl $(TIMER_SEL0|TIMER_LATCH),%eax + outb %al,$TIMER_MODE # latch timer 0's counter + + # + # Read counter value into ebx, LSB first + # + inb $TIMER_CNTR0,%al + movzbl %al,%ebx + inb $TIMER_CNTR0,%al + movzbl %al,%eax + sall $8,%eax + orl %eax,%ebx + + # + # Now check for counter overflow. This is tricky because the + # timer chip doesn't let us atomically read the current counter + # value and the output state (i.e., overflow state). We have + # to read the ICU interrupt request register (IRR) to see if the + # overflow has occured. Because we lack atomicity, we use + # the (very accurate) heuristic that we only check for + # overflow if the value read is close to the interrupt period. + # E.g., if we just checked the IRR, we might read a non-overflowing + # value close to 0, experience overflow, then read this overflow + # from the IRR, and mistakenly add a correction to the "close + # to zero" value. + # + # We compare the counter value to heuristic constant 11890. + # If the counter value is less than this, we assume the counter + # didn't overflow between disabling interrupts above and latching + # the counter value. For example, we assume that the above 10 or so + # instructions take less than 11932 - 11890 = 42 microseconds to + # execute. + # + # Otherwise, the counter might have overflowed. We check for this + # condition by reading the interrupt request register out of the ICU. + # If it overflowed, we add in one clock period. + # + # The heuristic is "very accurate" because it works 100% if + # we're called from an ipl less than the clock. Otherwise, + # it might not work. Currently, only gettimeofday and bpf + # call microtime so it's not a problem. + # + cmpl $11890,%ebx + jle 2f + movl $0x0a,%eax # tell ICU we want IRR + outb %al,$IO_ICU1 + + inb $IO_ICU1,%al # read IRR in ICU + testb $1,%al # is a timer interrupt pending? + je 1f + addl $-11932,%ebx # yes, subtract one clock period +1: + movl $0x0b,%eax # tell ICU we want ISR + outb %al,$IO_ICU1 # (rest of kernel expects this) +2: + sti # enable interrupts + + movl $11932,%eax # subtract counter value from 11932 since + subl %ebx,%eax # it is a count-down value + imull $1000,%eax,%eax + movl $0,%edx # zero extend eax for div + movl $1193,%ecx + idivl %ecx # convert to usecs: mult by 1000/1193 + + addl %eax,%esi # add counter usecs to time.tv_usec + cmpl $1000000,%esi # carry in timeval? + jl 3f + subl $1000000,%esi # adjust usec + incl %edi # bump sec +3: + movl 16(%esp),%ecx # load timeval pointer arg + movl %edi,(%ecx) # tvp->tv_sec = sec + movl %esi,4(%ecx) # tvp->tv_usec = usec + + popl %ebx # restore regs + popl %esi + popl %edi + ret +#endif diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c new file mode 100644 index 000000000000..66c7fec59a8d --- /dev/null +++ b/sys/i386/i386/pmap.c @@ -0,0 +1,1728 @@ +/* + * Copyright (c) 1991 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 William Jolitz of UUNET Technologies 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. + * + * @(#)pmap.c 7.7 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00063 + * -------------------- ----- ---------------------- + * + * 28 Nov 1991 Poul-Henning Kamp Speedup processing. + */ +static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/i386/RCS/pmap.c,v 1.3 92/01/21 14:26:44 william Exp Locker: root $"; + +/* + * Derived from hp300 version by Mike Hibler, this version by William + * Jolitz uses a recursive map [a pde points to the page directory] to + * map the page tables using the pagetables themselves. This is done to + * reduce the impact on kernel virtual memory for lots of sparse address + * space, and to reduce the cost of memory to each process. + * + * Derived from: hp300/@(#)pmap.c 7.1 (Berkeley) 12/5/90 + */ + +/* + * Reno i386 version, from Mike Hibler's hp300 version. + */ + +/* + * 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 "param.h" +#include "proc.h" +#include "malloc.h" +#include "user.h" + +#include "vm/vm.h" +#include "vm/vm_kern.h" +#include "vm/vm_page.h" +/*#include "vm/vm_pageout.h"*/ + +#include "i386/isa/isa.h" + +/* + * Allocate various and sundry SYSMAPs used in the days of old VM + * and not yet converted. XXX. + */ +#define BSDVM_COMPAT 1 + +#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 */ +} enter_stats; +struct { + int calls; + int removes; + int pvfirst; + int pvsearch; + int ptinvalid; + int uflushes; + int sflushes; +} remove_stats; + +int debugmap = 0; +int pmapdebug = 0 /* 0xffff */; +#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_CACHE 0x0040 +#define PDB_BITS 0x0080 +#define PDB_COLLECT 0x0100 +#define PDB_PROTECT 0x0200 +#define PDB_PDRTAB 0x0400 +#define PDB_PARANOIA 0x2000 +#define PDB_WIRING 0x4000 +#define PDB_PVDUMP 0x8000 + +int pmapvacflush = 0; +#define PVF_ENTER 0x01 +#define PVF_REMOVE 0x02 +#define PVF_PROTECT 0x04 +#define PVF_TOTAL 0x80 +#endif + +/* + * Get PDEs and PTEs for user/kernel address space + */ +#define pmap_pde(m, v) (&((m)->pm_pdir[((vm_offset_t)(v) >> PD_SHIFT)&1023])) + +#define pmap_pte_pa(pte) (*(int *)(pte) & PG_FRAME) + +#define pmap_pde_v(pte) ((pte)->pd_v) +#define pmap_pte_w(pte) ((pte)->pg_w) +/* #define pmap_pte_ci(pte) ((pte)->pg_ci) */ +#define pmap_pte_m(pte) ((pte)->pg_m) +#define pmap_pte_u(pte) ((pte)->pg_u) +#define pmap_pte_v(pte) ((pte)->pg_v) +#define pmap_pte_set_w(pte, v) ((pte)->pg_w = (v)) +#define pmap_pte_set_prot(pte, v) ((pte)->pg_prot = (v)) + +/* + * Given a map and a machine independent protection code, + * convert to a vax protection code. + */ +#define pte_prot(m, p) (protection_codes[p]) +int protection_codes[8]; + +struct pmap kernel_pmap_store; +pmap_t kernel_pmap; + +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) */ +vm_offset_t vm_first_phys; /* PA of first managed page */ +vm_offset_t vm_last_phys; /* PA just past last managed page */ +int i386pagesperpage; /* PAGE_SIZE / I386_PAGE_SIZE */ +boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */ +char *pmap_attributes; /* reference and modify bits */ + +boolean_t pmap_testbit(); +void pmap_clear_modify(); + +#if BSDVM_COMPAT +#include "msgbuf.h" + +/* + * All those kernel PT submaps that BSD is so fond of + */ +struct pte *CMAP1, *CMAP2, *mmap; +caddr_t CADDR1, CADDR2, vmmap; +struct pte *msgbufmap; +struct msgbuf *msgbufp; +#endif + +/* + * Bootstrap the system enough to run with virtual memory. + * Map the kernel's code and data, and allocate the system page table. + * + * On the I386 this is called after mapping has already been enabled + * and just syncs the pmap module with what has already been done. + * [We can't call it easily with mapping off since the kernel is not + * mapped with PA == VA, hence we would have to relocate every address + * from the linked base (virtual) address 0xFE000000 to the actual + * (physical) address starting relative to 0] + */ +struct pte *pmap_pte(); + +void +pmap_bootstrap(firstaddr, loadaddr) + vm_offset_t firstaddr; + vm_offset_t loadaddr; +{ +#if BSDVM_COMPAT + vm_offset_t va; + struct pte *pte; +#endif + extern vm_offset_t maxmem, physmem; +extern int IdlePTD; + + avail_start = firstaddr; + avail_end = maxmem << PG_SHIFT; + + /* XXX: allow for msgbuf */ + avail_end -= i386_round_page(sizeof(struct msgbuf)); + + mem_size = physmem << PG_SHIFT; + virtual_avail = (vm_offset_t)atdevbase + 0x100000 - 0xa0000 + 10*NBPG; + virtual_end = VM_MAX_KERNEL_ADDRESS; + i386pagesperpage = PAGE_SIZE / I386_PAGE_SIZE; + + /* + * Initialize protection array. + */ + i386_protection_init(); + + /* + * The kernel's pmap is statically allocated so we don't + * have to use pmap_create, which is unlikely to work + * correctly at this part of the boot sequence. + */ + kernel_pmap = &kernel_pmap_store; + +#ifdef notdef + /* + * Create Kernel page directory table and page maps. + * [ currently done in locore. i have wild and crazy ideas -wfj ] + */ + bzero(firstaddr, 4*NBPG); + kernel_pmap->pm_pdir = firstaddr + VM_MIN_KERNEL_ADDRESS; + kernel_pmap->pm_ptab = firstaddr + VM_MIN_KERNEL_ADDRESS + NBPG; + + firstaddr += NBPG; + for (x = i386_btod(VM_MIN_KERNEL_ADDRESS); + x < i386_btod(VM_MIN_KERNEL_ADDRESS)+3; x++) { + struct pde *pde; + pde = kernel_pmap->pm_pdir + x; + *(int *)pde = firstaddr + x*NBPG | PG_V | PG_KW; + } +#else + kernel_pmap->pm_pdir = (pd_entry_t *)(0xfe000000 + IdlePTD); +#endif + + + simple_lock_init(&kernel_pmap->pm_lock); + kernel_pmap->pm_count = 1; + +#if BSDVM_COMPAT + /* + * Allocate all the submaps we need + */ +#define SYSMAP(c, p, v, n) \ + v = (c)va; va += ((n)*I386_PAGE_SIZE); p = pte; pte += (n); + + va = virtual_avail; + pte = pmap_pte(kernel_pmap, va); + + SYSMAP(caddr_t ,CMAP1 ,CADDR1 ,1 ) + SYSMAP(caddr_t ,CMAP2 ,CADDR2 ,1 ) + SYSMAP(caddr_t ,mmap ,vmmap ,1 ) + SYSMAP(struct msgbuf * ,msgbufmap ,msgbufp ,1 ) + virtual_avail = va; +#endif + /* + * reserve special hunk of memory for use by bus dma as a bounce + * buffer (contiguous virtual *and* physical memory). for now, + * assume vm does not use memory beneath hole, and we know that + * the bootstrap uses top 32k of base memory. -wfj + */ + { + extern vm_offset_t isaphysmem; + isaphysmem = va; + + virtual_avail = pmap_map(va, 0xa0000 - 32*1024, 0xa0000, VM_PROT_ALL); + } + + *(int *)PTD = 0; + load_cr3(rcr3()); + +} + +/* + * 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; +{ + vm_offset_t addr, addr2; + vm_size_t npg, s; + int rv; + extern int KPTphys; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_init(%x, %x)\n", phys_start, phys_end); +#endif + /* + * Now that kernel map has been allocated, we can mark as + * unavailable regions which we have mapped in locore. + */ + addr = atdevbase; + (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0, + &addr, (0x100000-0xa0000), FALSE); + + addr = (vm_offset_t) 0xfe000000+KPTphys/* *NBPG */; + vm_object_reference(kernel_object); + (void) vm_map_find(kernel_map, kernel_object, addr, + &addr, 2*NBPG, FALSE); + + /* + * Allocate memory for random pmap data structures. Includes the + * pv_head_table and pmap_attributes. + */ + npg = atop(phys_end - phys_start); + s = (vm_size_t) (sizeof(struct pv_entry) * npg + npg); + s = round_page(s); + addr = (vm_offset_t) kmem_alloc(kernel_map, s); + pv_table = (pv_entry_t) addr; + addr += sizeof(struct pv_entry) * npg; + pmap_attributes = (char *) addr; +#ifdef DEBUG + if (pmapdebug & PDB_INIT) + printf("pmap_init: %x bytes (%x pgs): tbl %x attr %x\n", + s, npg, pv_table, pmap_attributes); +#endif + + /* + * Now it is safe to enable pv_table recording. + */ + vm_first_phys = phys_start; + vm_last_phys = phys_end; + pmap_initialized = TRUE; +} + +/* + * Used to map a range of physical addresses into kernel + * virtual address space. + * + * For now, VM is already on, we only need to map the + * specified memory. + */ +vm_offset_t +pmap_map(virt, start, end, prot) + vm_offset_t virt; + vm_offset_t start; + vm_offset_t end; + int prot; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_map(%x, %x, %x, %x)\n", virt, start, end, prot); +#endif + while (start < end) { + pmap_enter(kernel_pmap, virt, start, prot, FALSE); + virt += PAGE_SIZE; + start += PAGE_SIZE; + } + return(virt); +} + +/* + * 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. + * + * [ just allocate a ptd and mark it uninitialize -- should we track + * with a table which process has which ptd? -wfj ] + */ + +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; +{ + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + pg("pmap_pinit(%x)\n", pmap); +#endif + + /* + * No need to allocate page table space yet but we do need a + * valid page directory table. + */ + pmap->pm_pdir = (pd_entry_t *) kmem_alloc(kernel_map, NBPG); + + /* wire in kernel global address entries */ + bcopy(PTD+KPTDI_FIRST, pmap->pm_pdir+KPTDI_FIRST, + (KPTDI_LAST-KPTDI_FIRST+1)*4); + + /* install self-referential address mapping entry */ + *(int *)(pmap->pm_pdir+PTDPTDI) = + (int)pmap_extract(kernel_pmap, pmap->pm_pdir) | PG_V | PG_URKW; + + pmap->pm_count = 1; + simple_lock_init(&pmap->pm_lock); +} + +/* + * 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) + 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 struct pmap *pmap; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + pg("pmap_release(%x)\n", pmap); +#endif +#ifdef notdef /* DIAGNOSTIC */ + /* count would be 0 from pmap_destroy... */ + simple_lock(&pmap->pm_lock); + if (pmap->pm_count != 1) + panic("pmap_release count"); +#endif + kmem_free(kernel_map, (vm_offset_t)pmap->pm_pdir, NBPG); +} + +/* + * Add a reference to the specified pmap. + */ +void +pmap_reference(pmap) + pmap_t pmap; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_reference(%x)", 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) + struct pmap *pmap; + register vm_offset_t sva; + register vm_offset_t eva; +{ + register pt_entry_t *ptp,*ptq; + vm_offset_t va; + vm_offset_t pa; + pt_entry_t *pte; + pv_entry_t pv, npv; + int ix; + int s, bits; +#ifdef DEBUG + pt_entry_t opte; + + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + pg("pmap_remove(%x, %x, %x)", pmap, sva, eva); +#endif + + if (pmap == NULL) + return; + + /* are we current address space or kernel? */ + if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum + || pmap == kernel_pmap) + ptp=PTmap; + + /* otherwise, we are alternate address space */ + else { + if (pmap->pm_pdir[PTDPTDI].pd_pfnum + != APTDpde.pd_pfnum) { + APTDpde = pmap->pm_pdir[PTDPTDI]; + tlbflush(); + } + ptp=APTmap; + } +#ifdef DEBUG + remove_stats.calls++; +#endif + + /* this is essential since we must check the PDE(sva) for precense */ + while (sva <= eva && !pmap_pde_v(pmap_pde(pmap, sva))) + sva = (sva & PD_MASK) + (1<<PD_SHIFT); + sva = i386_btop(sva); + eva = i386_btop(eva); + + for (; sva < eva; sva++) { + /* + * Weed out invalid mappings. + * Note: we assume that the page directory table is + * always allocated, and in kernel virtual. + */ + ptq=ptp+sva; + while((sva & 0x3ff) && !pmap_pte_pa(ptq)) + { + if(++sva >= eva) + return; + ptq++; + } + + + if(!(sva & 0x3ff)) /* Only check once in a while */ + { + if (!pmap_pde_v(pmap_pde(pmap, i386_ptob(sva)))) + { + /* We can race ahead here, straight to next pde.. */ + sva = (sva & 0xffc00) + (1<<10) -1 ; + continue; + } + } + if(!pmap_pte_pa(ptp+sva)) + continue; + + pte = ptp + sva; + pa = pmap_pte_pa(pte); + va = i386_ptob(sva); +#ifdef DEBUG + opte = *pte; + remove_stats.removes++; +#endif + /* + * Update statistics + */ + if (pmap_pte_w(pte)) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + + /* + * Invalidate the PTEs. + * XXX: should cluster them up and invalidate as many + * as possible at once. + */ +#ifdef DEBUG + if (pmapdebug & PDB_REMOVE) + printf("remove: inv %x ptes at %x(%x) ", + i386pagesperpage, pte, *(int *)pte); +#endif + bits = ix = 0; + do { + bits |= *(int *)pte & (PG_U|PG_M); + *(int *)pte++ = 0; + /*TBIS(va + ix * I386_PAGE_SIZE);*/ + } while (++ix != i386pagesperpage); + if (curproc && pmap == &curproc->p_vmspace->vm_pmap) + pmap_activate(pmap, (struct pcb *)curproc->p_addr); + /* are we current address space or kernel? */ + /*if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum + || pmap == kernel_pmap) + load_cr3(curpcb->pcb_ptd);*/ + tlbflush(); + +#ifdef needednotdone +reduce wiring count on page table pages as references drop +#endif + + /* + * Remove from the PV table (raise IPL since we + * may be called at interrupt time). + */ + if (pa < vm_first_phys || pa >= vm_last_phys) + continue; + 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) { + 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 { + for (npv = pv->pv_next; npv; npv = npv->pv_next) { +#ifdef DEBUG + remove_stats.pvsearch++; +#endif + if (pmap == npv->pv_pmap && va == npv->pv_va) + break; + pv = npv; + } +#ifdef DEBUG + if (npv == NULL) + panic("pmap_remove: PA not in pv_tab"); +#endif + pv->pv_next = npv->pv_next; + free((caddr_t)npv, M_VMPVENT); + pv = pa_to_pvh(pa); + } + +#ifdef notdef +[tally number of pagetable pages, if sharing of ptpages adjust here] +#endif + /* + * Update saved attributes for managed page + */ + pmap_attributes[pa_index(pa)] |= bits; + splx(s); + } +#ifdef notdef +[cache and tlb flushing, if needed] +#endif +} + +/* + * Routine: pmap_remove_all + * Function: + * Removes this physical page from + * all physical maps in which it resides. + * Reflects back modify bits to the pager. + */ +void +pmap_remove_all(pa) + vm_offset_t pa; +{ + register pv_entry_t pv; + int s; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + printf("pmap_remove_all(%x)", pa); + /*pmap_pvdump(pa);*/ +#endif + /* + * Not one of ours + */ + if (pa < vm_first_phys || pa >= vm_last_phys) + return; + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Do it the easy way for now + */ + while (pv->pv_pmap != NULL) { +#ifdef DEBUG + if (!pmap_pde_v(pmap_pde(pv->pv_pmap, pv->pv_va)) || + pmap_pte_pa(pmap_pte(pv->pv_pmap, pv->pv_va)) != pa) + panic("pmap_remove_all: bad mapping"); +#endif + pmap_remove(pv->pv_pmap, pv->pv_va, pv->pv_va + PAGE_SIZE); + } + splx(s); +} + +/* + * Routine: pmap_copy_on_write + * Function: + * Remove write privileges from all + * physical maps for this physical page. + */ +void +pmap_copy_on_write(pa) + vm_offset_t pa; +{ +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) + printf("pmap_copy_on_write(%x)", pa); +#endif + pmap_changebit(pa, PG_RO, TRUE); +} + +/* + * 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 pt_entry_t *pte; + register vm_offset_t va; + register int ix; + int i386prot; + boolean_t firstpage = TRUE; + register pt_entry_t *ptp; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) + printf("pmap_protect(%x, %x, %x, %x)", pmap, sva, eva, prot); +#endif + if (pmap == NULL) + return; + + if ((prot & VM_PROT_READ) == VM_PROT_NONE) { + pmap_remove(pmap, sva, eva); + return; + } + if (prot & VM_PROT_WRITE) + return; + + /* are we current address space or kernel? */ + if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum + || pmap == kernel_pmap) + ptp=PTmap; + + /* otherwise, we are alternate address space */ + else { + if (pmap->pm_pdir[PTDPTDI].pd_pfnum + != APTDpde.pd_pfnum) { + APTDpde = pmap->pm_pdir[PTDPTDI]; + tlbflush(); + } + ptp=APTmap; + } + for (va = sva; va < eva; va += PAGE_SIZE) { + /* + * Page table page is not allocated. + * Skip it, we don't want to force allocation + * of unnecessary PTE pages just to set the protection. + */ + if (!pmap_pde_v(pmap_pde(pmap, va))) { + /* XXX: avoid address wrap around */ + if (va >= i386_trunc_pdr((vm_offset_t)-1)) + break; + va = i386_round_pdr(va + PAGE_SIZE) - PAGE_SIZE; + continue; + } + + pte = ptp + i386_btop(va); + + /* + * Page not valid. Again, skip it. + * Should we do this? Or set protection anyway? + */ + if (!pmap_pte_v(pte)) + continue; + + ix = 0; + i386prot = pte_prot(pmap, prot); + if(va < UPT_MAX_ADDRESS) + i386prot |= 2 /*PG_u*/; + do { + /* clear VAC here if PG_RO? */ + pmap_pte_set_prot(pte++, i386prot); + /*TBIS(va + ix * I386_PAGE_SIZE);*/ + } while (++ix != i386pagesperpage); + } + if (curproc && pmap == &curproc->p_vmspace->vm_pmap) + pmap_activate(pmap, (struct pcb *)curproc->p_addr); +} + +/* + * 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 int npte, ix; + vm_offset_t opa; + boolean_t cacheable = TRUE; + boolean_t checkpv = TRUE; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_ENTER)) + printf("pmap_enter(%x, %x, %x, %x, %x)", + pmap, va, pa, prot, wired); +#endif + if (pmap == NULL) + return; + + if(va > VM_MAX_KERNEL_ADDRESS)panic("pmap_enter: toobig"); + /* also, should not muck with PTD va! */ + +#ifdef DEBUG + if (pmap == kernel_pmap) + enter_stats.kernel++; + else + enter_stats.user++; +#endif + + /* + * Page Directory table entry not valid, we need a new PT page + */ + if (!pmap_pde_v(pmap_pde(pmap, va))) { + pg("ptdi %x", pmap->pm_pdir[PTDPTDI]); + } + + pte = pmap_pte(pmap, va); + opa = pmap_pte_pa(pte); +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: pte %x, *pte %x ", pte, *(int *)pte); +#endif + + /* + * Mapping has not changed, must be protection or wiring change. + */ + if (opa == pa) { +#ifdef DEBUG + enter_stats.pwchange++; +#endif + /* + * Wiring change, just update stats. + * We don't worry about wiring PT pages as they remain + * resident as long as there are valid mappings in them. + * Hence, if a user page is wired, the PT page will be also. + */ + if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) { +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + pg("enter: wiring change -> %x ", wired); +#endif + if (wired) + pmap->pm_stats.wired_count++; + else + pmap->pm_stats.wired_count--; +#ifdef DEBUG + enter_stats.wchange++; +#endif + } + goto validate; + } + + /* + * Mapping has changed, invalidate old range and fall through to + * handle validating new mapping. + */ + if (opa) { +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: removing old mapping %x pa %x ", va, opa); +#endif + pmap_remove(pmap, va, va + PAGE_SIZE); +#ifdef DEBUG + enter_stats.mchange++; +#endif + } + + /* + * Enter on the PV list if part of our managed memory + * Note that we raise IPL while manipulating pv_table + * since pmap_enter can be called at interrupt time. + */ + if (pa >= vm_first_phys && pa < vm_last_phys) { + register pv_entry_t pv, npv; + int s; + +#ifdef DEBUG + enter_stats.managed++; +#endif + pv = pa_to_pvh(pa); + s = splimp(); +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: pv at %x: %x/%x/%x ", + pv, pv->pv_va, pv->pv_pmap, pv->pv_next); +#endif + /* + * No entries yet, use header as the first entry + */ + if (pv->pv_pmap == NULL) { +#ifdef DEBUG + enter_stats.firstpv++; +#endif + pv->pv_va = va; + pv->pv_pmap = pmap; + pv->pv_next = NULL; + pv->pv_flags = 0; + } + /* + * There is at least one other VA mapping this page. + * Place this entry after the header. + */ + else { + /*printf("second time: ");*/ +#ifdef DEBUG + for (npv = pv; npv; npv = npv->pv_next) + if (pmap == npv->pv_pmap && va == npv->pv_va) + panic("pmap_enter: already in pv_tab"); +#endif + 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; + pv->pv_next = npv; +#ifdef DEBUG + if (!npv->pv_next) + enter_stats.secondpv++; +#endif + } + splx(s); + } + /* + * Assumption: if it is not part of our managed memory + * then it must be device memory which may be volitile. + */ + if (pmap_initialized) { + checkpv = cacheable = FALSE; +#ifdef DEBUG + enter_stats.unmanaged++; +#endif + } + + /* + * Increment counters + */ + pmap->pm_stats.resident_count++; + if (wired) + pmap->pm_stats.wired_count++; + +validate: + /* + * Now validate mapping with desired protection/wiring. + * Assume uniform modified and referenced status for all + * I386 pages in a MACH page. + */ + npte = (pa & PG_FRAME) | pte_prot(pmap, prot) | PG_V; + npte |= (*(int *)pte & (PG_M|PG_U)); + if (wired) + npte |= PG_W; + if(va < UPT_MIN_ADDRESS) + npte |= PG_u; + else if(va < UPT_MAX_ADDRESS) + npte |= PG_u | PG_RW; +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: new pte value %x ", npte); +#endif + ix = 0; + do { + *(int *)pte++ = npte; + /*TBIS(va);*/ + npte += I386_PAGE_SIZE; + va += I386_PAGE_SIZE; + } while (++ix != i386pagesperpage); + pte--; +#ifdef DEBUGx +cache, tlb flushes +#endif +/*pads(pmap);*/ + /*load_cr3(((struct pcb *)curproc->p_addr)->pcb_ptd);*/ + tlbflush(); +} + +/* + * pmap_page_protect: + * + * Lower the permission for all mappings to a given page. + */ +void +pmap_page_protect(phys, prot) + vm_offset_t phys; + vm_prot_t prot; +{ + switch (prot) { + case VM_PROT_READ: + case VM_PROT_READ|VM_PROT_EXECUTE: + pmap_copy_on_write(phys); + break; + case VM_PROT_ALL: + break; + default: + pmap_remove_all(phys); + break; + } +} + +/* + * 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; + register int ix; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_change_wiring(%x, %x, %x)", pmap, va, wired); +#endif + if (pmap == NULL) + return; + + pte = pmap_pte(pmap, va); +#ifdef DEBUG + /* + * Page table page is not allocated. + * Should this ever happen? Ignore it for now, + * we don't want to force allocation of unnecessary PTE pages. + */ + if (!pmap_pde_v(pmap_pde(pmap, va))) { + if (pmapdebug & PDB_PARANOIA) + pg("pmap_change_wiring: invalid PDE for %x ", va); + return; + } + /* + * Page not valid. Should this ever happen? + * Just continue and change wiring anyway. + */ + if (!pmap_pte_v(pte)) { + if (pmapdebug & PDB_PARANOIA) + pg("pmap_change_wiring: invalid PTE for %x ", va); + } +#endif + if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) { + if (wired) + pmap->pm_stats.wired_count++; + else + pmap->pm_stats.wired_count--; + } + /* + * Wiring is not a hardware characteristic so there is no need + * to invalidate TLB. + */ + ix = 0; + do { + pmap_pte_set_w(pte++, wired); + } while (++ix != i386pagesperpage); +} + +/* + * Routine: pmap_pte + * Function: + * Extract the page table entry associated + * with the given map/virtual_address pair. + * [ what about induced faults -wfj] + */ + +struct pte *pmap_pte(pmap, va) + register pmap_t pmap; + vm_offset_t va; +{ + +#ifdef DEBUGx + if (pmapdebug & PDB_FOLLOW) + printf("pmap_pte(%x, %x) ->\n", pmap, va); +#endif + if (pmap && pmap_pde_v(pmap_pde(pmap, va))) { + + /* are we current address space or kernel? */ + if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum + || pmap == kernel_pmap) + return ((struct pte *) vtopte(va)); + + /* otherwise, we are alternate address space */ + else { + if (pmap->pm_pdir[PTDPTDI].pd_pfnum + != APTDpde.pd_pfnum) { + APTDpde = pmap->pm_pdir[PTDPTDI]; + tlbflush(); + } + return((struct pte *) avtopte(va)); + } + } + return(0); +} + +/* + * 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 DEBUGx + if (pmapdebug & PDB_FOLLOW) + pg("pmap_extract(%x, %x) -> ", pmap, va); +#endif + pa = 0; + if (pmap && pmap_pde_v(pmap_pde(pmap, va))) { + pa = *(int *) pmap_pte(pmap, va); + } + if (pa) + pa = (pa & PG_FRAME) | (va & ~PG_FRAME); +#ifdef DEBUGx + if (pmapdebug & PDB_FOLLOW) + printf("%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)", + 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()"); +#endif + tlbflush(); +} + +/* + * 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. + * [ needs to be written -wfj ] + */ +void +pmap_collect(pmap) + pmap_t pmap; +{ + register vm_offset_t pa; + register pv_entry_t pv; + register int *pte; + vm_offset_t kpa; + int s; + +#ifdef DEBUG + int *pde; + int opmapdebug; + printf("pmap_collect(%x) ", pmap); +#endif + if (pmap != kernel_pmap) + return; + +} + +/* [ macro again?, should I force kstack into user map here? -wfj ] */ +void +pmap_activate(pmap, pcbp) + register pmap_t pmap; + struct pcb *pcbp; +{ +int x; +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PDRTAB)) + pg("pmap_activate(%x, %x) ", pmap, pcbp); +#endif + PMAP_ACTIVATE(pmap, pcbp); +/*printf("pde "); +for(x=0x3f6; x < 0x3fA; x++) + printf("%x ", pmap->pm_pdir[x]);*/ +/*pads(pmap);*/ +/*pg(" pcb_cr3 %x", pcbp->pcb_cr3);*/ +} + +/* + * Routine: pmap_kernel + * Function: + * Returns the physical map handle for the kernel. + */ +pmap_t +pmap_kernel() +{ + return (kernel_pmap); +} + +/* + * pmap_zero_page zeros the specified (machine independent) + * page by mapping the page into virtual memory and using + * bzero to clear its contents, one machine dependent page + * at a time. + */ +pmap_zero_page(phys) + register vm_offset_t phys; +{ + register int ix; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_zero_page(%x)", phys); +#endif + phys >>= PG_SHIFT; + ix = 0; + do { + clearseg(phys++); + } while (++ix != i386pagesperpage); +} + +/* + * pmap_copy_page copies the specified (machine independent) + * page by mapping the page into virtual memory and using + * bcopy to copy the page, one machine dependent page at a + * time. + */ +pmap_copy_page(src, dst) + register vm_offset_t src, dst; +{ + register int ix; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy_page(%x, %x)", src, dst); +#endif + src >>= PG_SHIFT; + dst >>= PG_SHIFT; + ix = 0; + do { + physcopyseg(src++, dst++); + } while (++ix != i386pagesperpage); +} + + +/* + * 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. + */ +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)", + pmap, sva, eva, pageable); +#endif + /* + * If we are making a PT page pageable then all valid + * mappings must be gone from that page. Hence it should + * be all zeros and there is no need to clean it. + * Assumptions: + * - we are called with only one page at a time + * - PT pages have only one pv_table entry + */ + if (pmap == kernel_pmap && pageable && sva + PAGE_SIZE == eva) { + register pv_entry_t pv; + register vm_offset_t pa; + +#ifdef DEBUG + if ((pmapdebug & (PDB_FOLLOW|PDB_PTPAGE)) == PDB_PTPAGE) + printf("pmap_pageable(%x, %x, %x, %x)", + pmap, sva, eva, pageable); +#endif + /*if (!pmap_pde_v(pmap_pde(pmap, sva))) + return;*/ + if(pmap_pte(pmap, sva) == 0) + return; + pa = pmap_pte_pa(pmap_pte(pmap, sva)); + if (pa < vm_first_phys || pa >= vm_last_phys) + return; + pv = pa_to_pvh(pa); + /*if (!ispt(pv->pv_va)) + return;*/ +#ifdef DEBUG + if (pv->pv_va != sva || pv->pv_next) { + pg("pmap_pageable: bad PT page va %x next %x\n", + pv->pv_va, pv->pv_next); + return; + } +#endif + /* + * Mark it unmodified to avoid pageout + */ + pmap_clear_modify(pa); +#ifdef needsomethinglikethis + if (pmapdebug & PDB_PTPAGE) + pg("pmap_pageable: PT page %x(%x) unmodified\n", + sva, *(int *)pmap_pte(pmap, sva)); + if (pmapdebug & PDB_WIRING) + pmap_check_wiring("pageable", sva); +#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)", pa); +#endif + pmap_changebit(pa, PG_M, FALSE); +} + +/* + * 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)", pa); +#endif + pmap_changebit(pa, PG_U, FALSE); +} + +/* + * 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 DEBUG + if (pmapdebug & PDB_FOLLOW) { + boolean_t rv = pmap_testbit(pa, PG_U); + printf("pmap_is_referenced(%x) -> %c", pa, "FT"[rv]); + return(rv); + } +#endif + return(pmap_testbit(pa, PG_U)); +} + +/* + * 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 DEBUG + if (pmapdebug & PDB_FOLLOW) { + boolean_t rv = pmap_testbit(pa, PG_M); + printf("pmap_is_modified(%x) -> %c", pa, "FT"[rv]); + return(rv); + } +#endif + return(pmap_testbit(pa, PG_M)); +} + +vm_offset_t +pmap_phys_address(ppn) + int ppn; +{ + return(i386_ptob(ppn)); +} + +/* + * Miscellaneous support routines follow + */ + +i386_protection_init() +{ + register int *kp, prot; + + kp = protection_codes; + for (prot = 0; prot < 8; prot++) { + switch (prot) { + case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE: + *kp++ = 0; + break; + case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE: + case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE: + case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE: + *kp++ = PG_RO; + break; + case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE: + case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE: + case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE: + case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE: + *kp++ = PG_RW; + break; + } + } +} + +boolean_t +pmap_testbit(pa, bit) + register vm_offset_t pa; + int bit; +{ + register pv_entry_t pv; + register int *pte, ix; + int s; + + if (pa < vm_first_phys || pa >= vm_last_phys) + return(FALSE); + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Check saved info first + */ + if (pmap_attributes[pa_index(pa)] & bit) { + splx(s); + return(TRUE); + } + /* + * Not found, check current mappings returning + * immediately if found. + */ + if (pv->pv_pmap != NULL) { + for (; pv; pv = pv->pv_next) { + pte = (int *) pmap_pte(pv->pv_pmap, pv->pv_va); + ix = 0; + do { + if (*pte++ & bit) { + splx(s); + return(TRUE); + } + } while (++ix != i386pagesperpage); + } + } + splx(s); + return(FALSE); +} + +pmap_changebit(pa, bit, setem) + register vm_offset_t pa; + int bit; + boolean_t setem; +{ + register pv_entry_t pv; + register int *pte, npte, ix; + vm_offset_t va; + int s; + boolean_t firstpage = TRUE; + +#ifdef DEBUG + if (pmapdebug & PDB_BITS) + printf("pmap_changebit(%x, %x, %s)", + pa, bit, setem ? "set" : "clear"); +#endif + if (pa < vm_first_phys || pa >= vm_last_phys) + return; + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Clear saved attributes (modify, reference) + */ + if (!setem) + pmap_attributes[pa_index(pa)] &= ~bit; + /* + * Loop over all current mappings setting/clearing as appropos + * If setting RO do we need to clear the VAC? + */ + if (pv->pv_pmap != NULL) { +#ifdef DEBUG + int toflush = 0; +#endif + for (; pv; pv = pv->pv_next) { +#ifdef DEBUG + toflush |= (pv->pv_pmap == kernel_pmap) ? 2 : 1; +#endif + va = pv->pv_va; + + /* + * XXX don't write protect pager mappings + */ + if (bit == PG_RO) { + extern vm_offset_t pager_sva, pager_eva; + + if (va >= pager_sva && va < pager_eva) + continue; + } + + pte = (int *) pmap_pte(pv->pv_pmap, va); + ix = 0; + do { + if (setem) + npte = *pte | bit; + else + npte = *pte & ~bit; + if (*pte != npte) { + *pte = npte; + /*TBIS(va);*/ + } + va += I386_PAGE_SIZE; + pte++; + } while (++ix != i386pagesperpage); + + if (curproc && pv->pv_pmap == &curproc->p_vmspace->vm_pmap) + pmap_activate(pv->pv_pmap, (struct pcb *)curproc->p_addr); + } +#ifdef somethinglikethis + if (setem && bit == PG_RO && (pmapvacflush & PVF_PROTECT)) { + if ((pmapvacflush & PVF_TOTAL) || toflush == 3) + DCIA(); + else if (toflush == 2) + DCIS(); + else + DCIU(); + } +#endif + } + splx(s); +} + +#ifdef DEBUG +pmap_pvdump(pa) + vm_offset_t pa; +{ + register pv_entry_t pv; + + printf("pa %x", pa); + for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) { + printf(" -> pmap %x, va %x, flags %x", + pv->pv_pmap, pv->pv_va, pv->pv_flags); + pads(pv->pv_pmap); + } + printf(" "); +} + +#ifdef notyet +pmap_check_wiring(str, va) + char *str; + vm_offset_t va; +{ + vm_map_entry_t entry; + register int count, *pte; + + va = trunc_page(va); + if (!pmap_pde_v(pmap_pde(kernel_pmap, va)) || + !pmap_pte_v(pmap_pte(kernel_pmap, va))) + return; + + if (!vm_map_lookup_entry(pt_map, va, &entry)) { + pg("wired_check: entry for %x not found\n", va); + return; + } + count = 0; + for (pte = (int *)va; pte < (int *)(va+PAGE_SIZE); pte++) + if (*pte) + count++; + if (entry->wired_count != count) + pg("*%s*: %x: w%d/a%d\n", + str, va, entry->wired_count, count); +} +#endif + +/* print address space of pmap*/ +pads(pm) pmap_t pm; { + unsigned va, i, j; + struct pte *ptep; + + if(pm == kernel_pmap) return; + for (i = 0; i < 1024; i++) + if(pm->pm_pdir[i].pd_v) + for (j = 0; j < 1024 ; j++) { + va = (i<<22)+(j<<12); + if (pm == kernel_pmap && va < 0xfe000000) + continue; + if (pm != kernel_pmap && va > UPT_MAX_ADDRESS) + continue; + ptep = pmap_pte(pm, va); + if(pmap_pte_v(ptep)) + printf("%x:%x ", va, *(int *)ptep); + } ; + +} +#endif diff --git a/sys/i386/i386/swapgeneric.c b/sys/i386/i386/swapgeneric.c new file mode 100644 index 000000000000..0d76e7280cc2 --- /dev/null +++ b/sys/i386/i386/swapgeneric.c @@ -0,0 +1,166 @@ +/*- + * 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 "machine/pte.h" + +#include "sys/param.h" +#include "sys/conf.h" +#include "sys/buf.h" +#include "sys/vm.h" +#include "sys/systm.h" +#include "sys/reboot.h" + +/* + * Generic configuration; all in one + */ +dev_t rootdev = makedev(0,0); +dev_t dumpdev = makedev(0,1); +int nswap; +struct swdevt swdevt[] = { + { 1, 0, 0 }, + { 0, 1, 0 }, +}; +long dumplo; +int dmmin, dmmax, dmtext; + +extern struct driver wddriver; + +struct genericconf { + caddr_t gc_driver; + char *gc_name; + dev_t gc_root; +} genericconf[] = { + { (caddr_t)&wddriver, "wd", makedev(0, 0), }, + { 0 }, +}; + +setconf() +{ +#ifdef notdef + register struct genericconf *gc; + int unit, swaponroot = 0; + + if (rootdev != NODEV) + goto doswap; + if (boothowto & RB_ASKNAME) { + char name[128]; +retry: + printf("root device? "); + gets(name); + 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 dk%%d\n"); + goto retry; + } + unit = 0; + for (gc = genericconf; gc->gc_driver; gc++) { + for (ui = vbdinit; ui->ui_driver; ui++) { + if (ui->ui_alive == 0) + continue; + if (ui->ui_unit == 0 && ui->ui_driver == + (struct vba_driver *)gc->gc_driver) { + printf("root on %s0\n", + ui->ui_driver->ud_dname); + goto found; + } + } + } + printf("no suitable root\n"); + asm("halt"); +found: + gc->gc_root = makedev(major(gc->gc_root), unit*8); + rootdev = gc->gc_root; +doswap: + swdevt[0].sw_dev = argdev = dumpdev = + makedev(major(rootdev), minor(rootdev)+1); + /* swap size and dumplo set during autoconfigure */ + if (swaponroot) + rootdev = dumpdev; +#endif +} + +gets(cp) + char *cp; +{ + register char *lp; + register c; + + lp = cp; + for (;;) { + printf("%c", c = cngetc()&0177); + switch (c) { + case '\n': + case '\r': + *lp++ = '\0'; + return; + case '\b': + case '\177': + if (lp > cp) { + printf(" \b"); + lp--; + } + continue; + case '#': + lp--; + if (lp < cp) + lp = cp; + continue; + case '@': + case 'u'&037: + lp = cp; + printf("%c", '\n'); + continue; + default: + *lp++ = c; + } + } +} diff --git a/sys/i386/i386/symbols.raw b/sys/i386/i386/symbols.raw new file mode 100644 index 000000000000..56e5ab4bc5ad --- /dev/null +++ b/sys/i386/i386/symbols.raw @@ -0,0 +1,89 @@ +# @(#)symbols.raw 7.6 (Berkeley) 5/8/91 +# +# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE +# -------------------- ----- ---------------------- +# CURRENT PATCH LEVEL: 1 00066 +# -------------------- ----- ---------------------- +# +# 28 Nov 1991 Warren Toomey Let symorder -t keep some needed +# symbols used by common programs +# + + +#gdb + _IdlePTD + _PTD + _curpcb + _kstack + _panicstr + _atdevbase +# _version +#dmesg + _msgbufp +# _msgbuf +#iostat + _dk_busy + _dk_time + _dk_xfer + _dk_wds + _tk_nin + _tk_nout + _dk_seek + _cp_time + _dk_wpms +# _io_info +#ps + _nswap + _maxslp + _ccpu + _fscale + _avail_start + _avail_end +#pstat +# _cons + _nswap + _swapmap +#vmstat + _cp_time + _rate + _total + _sum +# _rectime +# _pgintime + _dk_xfer + _boottime +#w + _swapdev + _nswap + _averunnable + _boottime +#netstat + _mbstat + _ipstat + _tcb + _tcpstat + _udb + _udpstat + _rawcb + _Sysmap + _ifnet + _rthost + _rtnet + _icmpstat + _filehead + _nfiles + _rthashsize +#routed + _ifnet +#rwho + _boottime +#savecore + _dumpdev + _dumplo + _version + _time + _dumpsize + _panicstr + _dumpmag +#deprecated +# _avenrun diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c new file mode 100644 index 000000000000..10b9ac274b40 --- /dev/null +++ b/sys/i386/i386/sys_machdep.c @@ -0,0 +1,105 @@ + +/*- + * 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. + * + * @(#)sys_machdep.c 5.5 (Berkeley) 1/19/91 + */ + +#include "param.h" +#include "systm.h" +#include "ioctl.h" +#include "file.h" +#include "time.h" +#include "proc.h" +#include "uio.h" +#include "kernel.h" +#include "mtio.h" +#include "buf.h" +#include "trace.h" + +#ifdef TRACE +int nvualarm; + +vtrace(p, uap, retval) + struct proc *p; + register struct args { + int request; + int value; + } *uap; + int *retval; +{ + int vdoualarm(); + + switch (uap->request) { + + case VTR_DISABLE: /* disable a trace point */ + case VTR_ENABLE: /* enable a trace point */ + if (uap->value < 0 || uap->value >= TR_NFLAGS) + return (EINVAL); + *retval = traceflags[uap->value]; + traceflags[uap->value] = uap->request; + break; + + case VTR_VALUE: /* return a trace point setting */ + if (uap->value < 0 || uap->value >= TR_NFLAGS) + return (EINVAL); + *retval = traceflags[uap->value]; + break; + + case VTR_UALARM: /* set a real-time ualarm, less than 1 min */ + if (uap->value <= 0 || uap->value > 60 * hz || nvualarm > 5) + return (EINVAL); + nvualarm++; + timeout(vdoualarm, (caddr_t)p->p_pid, uap->value); + break; + + case VTR_STAMP: + trace(TR_STAMP, 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 diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c new file mode 100644 index 000000000000..57195f32cb91 --- /dev/null +++ b/sys/i386/i386/trap.c @@ -0,0 +1,547 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the University of Utah, and 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. + * + * @(#)trap.c 7.4 (Berkeley) 5/13/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00137 + * -------------------- ----- ---------------------- + * + * 08 Apr 93 Bruce Evans Several VM system fixes + * Paul Kranenburg Add counter for vmstat + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/trap.c,v 1.2 92/01/21 14:22:13 william Exp $"; + +/* + * 386 Trap and System call handleing + */ + +#include "machine/cpu.h" +#include "machine/psl.h" +#include "machine/reg.h" + +#include "param.h" +#include "systm.h" +#include "proc.h" +#include "user.h" +#include "acct.h" +#include "kernel.h" +#ifdef KTRACE +#include "ktrace.h" +#endif + +#include "vm/vm_param.h" +#include "vm/pmap.h" +#include "vm/vm_map.h" +#include "sys/vmmeter.h" + +#include "machine/trap.h" + + +struct sysent sysent[]; +int nsysent; +int dostacklimits; +unsigned rcr2(); +extern short cpl; + + +/* + * trap(frame): + * Exception, fault, and trap interface to BSD kernel. This + * common code is called from assembly language IDT gate entry + * routines that prepare a suitable stack frame, and restore this + * frame after the exception has been processed. Note that the + * effect is as if the arguments were passed call by reference. + */ + +/*ARGSUSED*/ +trap(frame) + struct trapframe frame; +{ + register int i; + register struct proc *p = curproc; + struct timeval syst; + int ucode, type, code, eva; + + frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */ + type = frame.tf_trapno; +#include "ddb.h" +#if NDDB > 0 + if (curpcb && curpcb->pcb_onfault) { + if (frame.tf_trapno == T_BPTFLT + || frame.tf_trapno == T_TRCTRAP) + if (kdb_trap (type, 0, &frame)) + return; + } +#endif + +/*pg("trap type %d code = %x eip = %x cs = %x eva = %x esp %x", + frame.tf_trapno, frame.tf_err, frame.tf_eip, + frame.tf_cs, rcr2(), frame.tf_esp);*/ +if(curpcb == 0 || curproc == 0) goto we_re_toast; + if (curpcb->pcb_onfault && frame.tf_trapno != 0xc) { +copyfault: + frame.tf_eip = (int)curpcb->pcb_onfault; + return; + } + + syst = p->p_stime; + if (ISPL(frame.tf_cs) == SEL_UPL) { + type |= T_USER; + p->p_regs = (int *)&frame; + curpcb->pcb_flags |= FM_TRAP; /* used by sendsig */ + } + + ucode=0; + eva = rcr2(); + code = frame.tf_err; + switch (type) { + + default: + we_re_toast: +#ifdef KDB + if (kdb_trap(&psl)) + return; +#endif +#if NDDB > 0 + if (kdb_trap (type, 0, &frame)) + return; +#endif + + printf("trap type %d code = %x eip = %x cs = %x eflags = %x ", + frame.tf_trapno, frame.tf_err, frame.tf_eip, + frame.tf_cs, frame.tf_eflags); + eva = rcr2(); + printf("cr2 %x cpl %x\n", eva, cpl); + /* type &= ~T_USER; */ /* XXX what the hell is this */ + panic("trap"); + /*NOTREACHED*/ + + case T_SEGNPFLT|T_USER: + case T_STKFLT|T_USER: + case T_PROTFLT|T_USER: /* protection fault */ + ucode = code + BUS_SEGM_FAULT ; + i = SIGBUS; + break; + + case T_PRIVINFLT|T_USER: /* privileged instruction fault */ + case T_RESADFLT|T_USER: /* reserved addressing fault */ + case T_RESOPFLT|T_USER: /* reserved operand fault */ + case T_FPOPFLT|T_USER: /* coprocessor operand fault */ + ucode = type &~ T_USER; + i = SIGILL; + break; + + case T_ASTFLT|T_USER: /* Allow process switch */ + astoff(); + cnt.v_soft++; + if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) { + addupc(frame.tf_eip, &p->p_stats->p_prof, 1); + p->p_flag &= ~SOWEUPC; + } + goto out; + + case T_DNA|T_USER: +#ifdef NPX + /* if a transparent fault (due to context switch "late") */ + if (npxdna()) return; +#endif + i = math_emulate(&frame); + if (i == 0) return; + ucode = FPE_FPU_NP_TRAP; + break; + + case T_BOUND|T_USER: + ucode = FPE_SUBRNG_TRAP; + i = SIGFPE; + break; + + case T_OFLOW|T_USER: + ucode = FPE_INTOVF_TRAP; + i = SIGFPE; + break; + + case T_DIVIDE|T_USER: + ucode = FPE_INTDIV_TRAP; + i = SIGFPE; + break; + + case T_ARITHTRAP|T_USER: + ucode = code; + i = SIGFPE; + break; + + case T_PAGEFLT: /* allow page faults in kernel mode */ +#if 0 + /* XXX - check only applies to 386's and 486's with WP off */ + if (code & PGEX_P) goto we_re_toast; +#endif + + /* fall into */ + case T_PAGEFLT|T_USER: /* page fault */ + { + register vm_offset_t va; + register struct vmspace *vm = p->p_vmspace; + register vm_map_t map; + int rv; + vm_prot_t ftype; + extern vm_map_t kernel_map; + unsigned nss,v; + + va = trunc_page((vm_offset_t)eva); + /* + * Avoid even looking at pde_v(va) for high va's. va's + * above VM_MAX_KERNEL_ADDRESS don't correspond to normal + * PDE's (half of them correspond to APDEpde and half to + * an unmapped kernel PDE). va's betweeen 0xFEC00000 and + * VM_MAX_KERNEL_ADDRESS correspond to unmapped kernel PDE's + * (XXX - why are only 3 initialized when 6 are required to + * reach VM_MAX_KERNEL_ADDRESS?). Faulting in an unmapped + * kernel page table would give inconsistent PTD's. + * + * XXX - faulting in unmapped page tables wastes a page if + * va turns out to be invalid. + * + * XXX - should "kernel address space" cover the kernel page + * tables? Might have same problem with PDEpde as with + * APDEpde (or there may be no problem with APDEpde). + */ + if (va > 0xFEBFF000) { + rv = KERN_FAILURE; /* becomes SIGBUS */ + goto nogo; + } + /* + * It is only a kernel address space fault iff: + * 1. (type & T_USER) == 0 and + * 2. pcb_onfault not set or + * 3. pcb_onfault set but supervisor space fault + * The last can occur during an exec() copyin where the + * argument space is lazy-allocated. + */ + if (type == T_PAGEFLT && va >= KERNBASE) + map = kernel_map; + else + map = &vm->vm_map; + if (code & PGEX_W) + ftype = VM_PROT_READ | VM_PROT_WRITE; + else + ftype = VM_PROT_READ; + +#ifdef DEBUG + if (map == kernel_map && va == 0) { + printf("trap: bad kernel access at %x\n", va); + goto we_re_toast; + } +#endif + + /* + * XXX: rude hack to make stack limits "work" + */ + nss = 0; + if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map + && dostacklimits) { + nss = clrnd(btoc((unsigned)vm->vm_maxsaddr + + MAXSSIZ - (unsigned)va)); + if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) { +/*pg("trap rlimit %d, maxsaddr %x va %x ", nss, vm->vm_maxsaddr, va);*/ + rv = KERN_FAILURE; + goto nogo; + } + } + + /* check if page table is mapped, if not, fault it first */ +#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v) + if (!pde_v(va)) { + v = trunc_page(vtopte(va)); + rv = vm_fault(map, v, ftype, FALSE); + if (rv != KERN_SUCCESS) goto nogo; + /* check if page table fault, increment wiring */ + vm_map_pageable(map, v, round_page(v+1), FALSE); + } else v=0; + rv = vm_fault(map, va, ftype, FALSE); + if (rv == KERN_SUCCESS) { + /* + * XXX: continuation of rude stack hack + */ + if (nss > vm->vm_ssize) + vm->vm_ssize = nss; + va = trunc_page(vtopte(va)); + /* for page table, increment wiring + as long as not a page table fault as well */ + if (!v && type != T_PAGEFLT) + vm_map_pageable(map, va, round_page(va+1), FALSE); + if (type == T_PAGEFLT) + return; + goto out; + } +nogo: + if (type == T_PAGEFLT) { + if (curpcb->pcb_onfault) + goto copyfault; + printf("vm_fault(%x, %x, %x, 0) -> %x\n", + map, va, ftype, rv); + printf(" type %x, code %x\n", + type, code); + goto we_re_toast; + } + i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; + break; + } + +#if NDDB == 0 + case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */ + frame.tf_eflags &= ~PSL_T; + + /* Q: how do we turn it on again? */ + return; +#endif + + case T_BPTFLT|T_USER: /* bpt instruction fault */ + case T_TRCTRAP|T_USER: /* trace trap */ + frame.tf_eflags &= ~PSL_T; + i = SIGTRAP; + break; + +#include "isa.h" +#if NISA > 0 + case T_NMI: + case T_NMI|T_USER: +#if NDDB > 0 + /* NMI can be hooked up to a pushbutton for debugging */ + printf ("NMI ... going to debugger\n"); + if (kdb_trap (type, 0, &frame)) + return; +#endif + /* machine/parity/power fail/"kitchen sink" faults */ + if(isa_nmi(code) == 0) return; + else goto we_re_toast; +#endif + } + + trapsignal(p, i, ucode); + if ((type & T_USER) == 0) + return; +out: + while (i = CURSIG(p)) + psig(i); + p->p_pri = p->p_usrpri; + if (want_resched) { + /* + * 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 setrq ourselves but before we + * swtch()'ed, we might not be on the queue indicated by + * our priority. + */ + (void) splclock(); + setrq(p); + p->p_stats->p_ru.ru_nivcsw++; + swtch(); + (void) splnone(); + while (i = CURSIG(p)) + psig(i); + } + if (p->p_stats->p_prof.pr_scale) { + int ticks; + struct timeval *tv = &p->p_stime; + + ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + + (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); + if (ticks) { +#ifdef PROFTIMER + extern int profscale; + addupc(frame.tf_eip, &p->p_stats->p_prof, + ticks * profscale); +#else + addupc(frame.tf_eip, &p->p_stats->p_prof, ticks); +#endif + } + } + curpri = p->p_pri; + curpcb->pcb_flags &= ~FM_TRAP; /* used by sendsig */ +} + +/* + * Compensate for 386 brain damage (missing URKR) + */ +int trapwrite(unsigned addr) { + int rv; + vm_offset_t va; + + va = trunc_page((vm_offset_t)addr); + if (va > VM_MAXUSER_ADDRESS) return(1); + rv = vm_fault(&curproc->p_vmspace->vm_map, va, + VM_PROT_READ | VM_PROT_WRITE, FALSE); + if (rv == KERN_SUCCESS) return(0); + else return(1); +} + +/* + * syscall(frame): + * System call request from POSIX system call gate interface to kernel. + * Like trap(), argument is call by reference. + */ +/*ARGSUSED*/ +syscall(frame) + volatile struct syscframe frame; +{ + register int *locr0 = ((int *)&frame); + register caddr_t params; + register int i; + register struct sysent *callp; + register struct proc *p = curproc; + struct timeval syst; + int error, opc; + int args[8], rval[2]; + int code; + +#ifdef lint + r0 = 0; r0 = r0; r1 = 0; r1 = r1; +#endif + syst = p->p_stime; + if (ISPL(frame.sf_cs) != SEL_UPL) + panic("syscall"); + + code = frame.sf_eax; + curpcb->pcb_flags &= ~FM_TRAP; /* used by sendsig */ + p->p_regs = (int *)&frame; + params = (caddr_t)frame.sf_esp + sizeof (int) ; + + /* + * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always. + */ + opc = frame.sf_eip - 7; + callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; + if (callp == sysent) { + i = fuword(params); + params += sizeof (int); + callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; + } + + if ((i = callp->sy_narg * sizeof (int)) && + (error = copyin(params, (caddr_t)args, (u_int)i))) { + frame.sf_eax = error; + frame.sf_eflags |= PSL_C; /* carry bit */ +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, callp->sy_narg, &args); +#endif + goto done; + } +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, callp->sy_narg, &args); +#endif + rval[0] = 0; + rval[1] = frame.sf_edx; +/*pg("%d. s %d\n", p->p_pid, code);*/ + error = (*callp->sy_call)(p, args, rval); + if (error == ERESTART) + frame.sf_eip = opc; + else if (error != EJUSTRETURN) { + if (error) { +/*pg("error %d", error);*/ + frame.sf_eax = error; + frame.sf_eflags |= PSL_C; /* carry bit */ + } else { + frame.sf_eax = rval[0]; + frame.sf_edx = rval[1]; + frame.sf_eflags &= ~PSL_C; /* carry bit */ + } + } + /* else if (error == EJUSTRETURN) */ + /* nothing to do */ +done: + /* + * Reinitialize proc pointer `p' as it may be different + * if this is a child returning from fork syscall. + */ + p = curproc; + while (i = CURSIG(p)) + psig(i); + p->p_pri = p->p_usrpri; + if (want_resched) { + /* + * 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 setrq ourselves but before we + * swtch()'ed, we might not be on the queue indicated by + * our priority. + */ + (void) splclock(); + setrq(p); + p->p_stats->p_ru.ru_nivcsw++; + swtch(); + (void) splnone(); + while (i = CURSIG(p)) + psig(i); + } + if (p->p_stats->p_prof.pr_scale) { + int ticks; + struct timeval *tv = &p->p_stime; + + ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + + (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); + if (ticks) { +#ifdef PROFTIMER + extern int profscale; + addupc(frame.sf_eip, &p->p_stats->p_prof, + ticks * profscale); +#else + addupc(frame.sf_eip, &p->p_stats->p_prof, ticks); +#endif + } + } + curpri = p->p_pri; +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(p->p_tracep, code, error, rval[0]); +#endif +#ifdef DIAGNOSTICx +{ extern int _udatasel, _ucodesel; + if (frame.sf_ss != _udatasel) + printf("ss %x call %d\n", frame.sf_ss, code); + if ((frame.sf_cs&0xffff) != _ucodesel) + printf("cs %x call %d\n", frame.sf_cs, code); + if (frame.sf_eip > VM_MAXUSER_ADDRESS) { + printf("eip %x call %d\n", frame.sf_eip, code); + frame.sf_eip = 0; + } +} +#endif +} diff --git a/sys/i386/i386/tsc.c b/sys/i386/i386/tsc.c new file mode 100644 index 000000000000..0fb77012d090 --- /dev/null +++ b/sys/i386/i386/tsc.c @@ -0,0 +1,271 @@ +/*- + * 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. + * + * @(#)clock.c 7.2 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 5 00158 + * -------------------- ----- ---------------------- + * + * 14 Aug 92 Arne Henrik Juul Added code in the kernel to + * allow for DST in the BIOS. + * 17 Jan 93 Bruce Evans Fixed leap year and second + * calculations + * 01 Feb 93 Julian Elischer Added code to for the cpu + * speed independent spinwait() + * function, (used by scsi and others) + * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1 + * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock + * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait + * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I + * still kept the other fixes... Had to + * add back in findcpuspeed that Bruce + * had removed. + */ + +/* + * Primitive clock interrupt routines. + */ +#include "param.h" +#include "systm.h" +#include "time.h" +#include "kernel.h" +#include "machine/segments.h" +#include "i386/isa/icu.h" +#include "i386/isa/isa.h" +#include "i386/isa/rtc.h" +#include "i386/isa/timerreg.h" + +#define DAYST 119 +#define DAYEN 303 + +/* X-tals being what they are, it's nice to be able to fudge this one... */ +/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */ +#ifndef TIMER_FREQ +#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */ +#endif + +startrtclock() { + int s; + + findcpuspeed(); /* use the clock (while it's free) + to find the cpu speed */ + /* initialize 8253 clock */ + outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); + + /* Correct rounding will buy us a better precision in timekeeping */ + outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz); + outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256); + + /* initialize brain-dead battery powered clock */ + outb (IO_RTC, RTC_STATUSA); + outb (IO_RTC+1, 0x26); + outb (IO_RTC, RTC_STATUSB); + outb (IO_RTC+1, 2); + + outb (IO_RTC, RTC_DIAG); + if (s = inb (IO_RTC+1)) + printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); + outb (IO_RTC, RTC_DIAG); + outb (IO_RTC+1, 0); +} + +unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ + +#define FIRST_GUESS 0x2000 +findcpuspeed() +{ + unsigned char low; + unsigned int remainder; + + /* Put counter in count down mode */ + outb(IO_TIMER1+3, 0x34); + outb(IO_TIMER1, 0xff); + outb(IO_TIMER1, 0xff); + delaycount = FIRST_GUESS; + spinwait(1); + /* Read the value left in the counter */ + low = inb(IO_TIMER1); /* least siginifcant */ + remainder = inb(IO_TIMER1); /* most significant */ + remainder = (remainder<<8) + low ; + /* Formula for delaycount is : + * (loopcount * timer clock speed)/ (counter ticks * 1000) + */ + delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder); +} + + +/* convert 2 digit BCD number */ +bcd(i) +int i; +{ + return ((i/16)*10 + (i%16)); +} + +/* convert years to seconds (from 1970) */ +unsigned long +ytos(y) +int y; +{ + int i; + unsigned long ret; + + ret = 0; + for(i = 1970; i < y; i++) { + if (i % 4) ret += 365*24*60*60; + else ret += 366*24*60*60; + } + return ret; +} + +/* convert months to seconds */ +unsigned long +mtos(m,leap) +int m,leap; +{ + int i; + unsigned long ret; + + ret = 0; + for(i=1;i<m;i++) { + switch(i){ + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + ret += 31*24*60*60; break; + case 4: case 6: case 9: case 11: + ret += 30*24*60*60; break; + case 2: + if (leap) ret += 29*24*60*60; + else ret += 28*24*60*60; + } + } + return ret; +} + + +/* + * Initialize the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +inittodr(base) + time_t base; +{ + unsigned long sec; + int leap,day_week,t,yd; + int sa,s; + + /* do we have a realtime clock present? (otherwise we loop below) */ + sa = rtcin(RTC_STATUSA); + if (sa == 0xff || sa == 0) return; + + /* ready for a read? */ + while ((sa&RTCSA_TUP) == RTCSA_TUP) + sa = rtcin(RTC_STATUSA); + + sec = bcd(rtcin(RTC_YEAR)) + 1900; + if (sec < 1970) + sec += 100; + leap = !(sec % 4); sec = ytos(sec); /* year */ + yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */ + t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */ + day_week = rtcin(RTC_WDAY); /* day */ + sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */ + sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */ + sec += bcd(rtcin(RTC_SEC)); /* seconds */ + + /* XXX off by one? Need to calculate DST on SUNDAY */ + /* Perhaps we should have the RTC hold GMT time to save */ + /* us the bother of converting. */ + yd = yd / (24*60*60); + if ((yd >= DAYST) && ( yd <= DAYEN)) { + sec -= 60*60; + } + sec += tz.tz_minuteswest * 60; + + time.tv_sec = sec; +} + +#ifdef garbage +/* + * Initialze the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +test_inittodr(base) + time_t base; +{ + + outb(IO_RTC,9); /* year */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,8); /* month */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,7); /* day */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,4); /* hour */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,2); /* minutes */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,0); /* seconds */ + printf("%d\n",bcd(inb(IO_RTC+1))); + + time.tv_sec = base; +} +#endif + +/* + * Restart the clock. + */ +resettodr() +{ +} + +/* + * Wire clock interrupt in. + */ +#define V(s) __CONCAT(V, s) +extern V(clk)(); +enablertclock() { + setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); + INTREN(IRQ0); +} + +/* + * Delay for some number of milliseconds. + */ +void +spinwait(millisecs) + int millisecs; +{ + DELAY(1000 * millisecs); +} diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c new file mode 100644 index 000000000000..27ef912e8519 --- /dev/null +++ b/sys/i386/i386/vm_machdep.c @@ -0,0 +1,410 @@ +/*- + * Copyright (c) 1982, 1986 The Regents of the University of California. + * Copyright (c) 1989, 1990 William Jolitz + * 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 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. + * + * @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Bruce Evans New npx-0.5 code + * + */ + +/* + * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/vm_machdep.c,v 1.2 92/01/21 14:22:17 william Exp $"; + +#include "param.h" +#include "systm.h" +#include "proc.h" +#include "malloc.h" +#include "buf.h" +#include "user.h" + +#include "../include/cpu.h" + +#include "vm/vm.h" +#include "vm/vm_kern.h" + +/* + * 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; + int foo, offset, addr, i; + extern char kstack[]; + extern int mvesp(); + + /* + * 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; + * this is tricky, as the final pcb is constructed by savectx, + * but its frame isn't yet on the stack when the stack is copied. + * swtch compensates for this when the child eventually runs. + * This should be done differently, with a single call + * that copies and updates the pcb+stack, + * replacing the bcopy and savectx. + */ + p2->p_addr->u_pcb = p1->p_addr->u_pcb; + offset = mvesp() - (int)kstack; + bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset, + (unsigned) ctob(UPAGES) - offset); + p2->p_regs = p1->p_regs; + + /* + * Wire top of address space of child to it's kstack. + * First, fault in a page of pte's to map it. + */ + addr = trunc_page((u_int)vtopte(kstack)); + vm_map_pageable(&p2->p_vmspace->vm_map, addr, addr+NBPG, FALSE); + for (i=0; i < UPAGES; i++) + pmap_enter(&p2->p_vmspace->vm_pmap, kstack+i*NBPG, + pmap_extract(kernel_pmap, ((int)p2->p_addr)+i*NBPG), VM_PROT_READ, 1); + + pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb); + + /* + * + * Arrange for a non-local goto when the new process + * is started, to resume here, returning nonzero from setjmp. + */ + if (savectx(up, 1)) { + /* + * Return 1 in child. + */ + return (1); + } + return (0); +} + +#ifdef notyet +/* + * cpu_exit is called as the last action during exit. + * + * We change to an inactive address space and a "safe" stack, + * passing thru an argument to the new stack. Now, safely isolated + * from the resources we're shedding, we release the address space + * and any remaining machine-dependent resources, including the + * memory for the user structure and kernel stack. + * + * Next, we assign a dummy context to be written over by swtch, + * calling it to send this process off to oblivion. + * [The nullpcb allows us to minimize cost in swtch() by not having + * a special case]. + */ +struct proc *swtch_to_inactive(); +cpu_exit(p) + register struct proc *p; +{ + static struct pcb nullpcb; /* pcb to overwrite on last swtch */ + +#ifdef NPX + npxexit(p); +#endif + + /* move to inactive space and stack, passing arg accross */ + p = swtch_to_inactive(p); + + /* drop per-process resources */ + vmspace_free(p->p_vmspace); + kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES)); + + p->p_addr = (struct user *) &nullpcb; + splclock(); + swtch(); + /* NOTREACHED */ +} +#else +cpu_exit(p) + register struct proc *p; +{ + +#ifdef NPX + npxexit(p); +#endif + splclock(); + swtch(); +} + +cpu_wait(p) struct proc *p; { + + /* drop per-process resources */ + vmspace_free(p->p_vmspace); + kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES)); +} +#endif + +/* + * Set a red zone in the kernel stack after the u. area. + */ +setredzone(pte, vaddr) + u_short *pte; + caddr_t vaddr; +{ +/* eventually do this by setting up an expand-down stack segment + for ss0: selector, allowing stack access down to top of u. + this means though that protection violations need to be handled + thru a double fault exception that must do an integral task + switch to a known good context, within which a dump can be + taken. a sensible scheme might be to save the initial context + used by sched (that has physical memory mapped 1:1 at bottom) + and take the dump while still in mapped mode */ +} + +/* + * 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. + */ +pagemove(from, to, size) + register caddr_t from, to; + int size; +{ + register struct pte *fpte, *tpte; + + if (size % CLBYTES) + panic("pagemove"); + fpte = kvtopte(from); + tpte = kvtopte(to); + while (size > 0) { + *tpte++ = *fpte; + *(int *)fpte++ = 0; + from += NBPG; + to += NBPG; + size -= NBPG; + } + tlbflush(); +} + +/* + * Convert kernel VA to physical address + */ +kvtop(addr) + register caddr_t addr; +{ + vm_offset_t va; + + va = pmap_extract(kernel_pmap, (vm_offset_t)addr); + if (va == 0) + panic("kvtop: zero page frame"); + return((int)va); +} + +#ifdef notdef +/* + * The probe[rw] routines should probably be redone in assembler + * for efficiency. + */ +prober(addr) + register u_int addr; +{ + register int page; + register struct proc *p; + + if (addr >= USRSTACK) + return(0); + p = u.u_procp; + page = btop(addr); + if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize)) + return(1); + return(0); +} + +probew(addr) + register u_int addr; +{ + register int page; + register struct proc *p; + + if (addr >= USRSTACK) + return(0); + p = u.u_procp; + page = btop(addr); + if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize)) + return((*(int *)vtopte(p, page) & PG_PROT) == PG_UW); + return(0); +} + +/* + * NB: assumes a physically contiguous kernel page table + * (makes life a LOT simpler). + */ +kernacc(addr, count, rw) + register u_int addr; + int count, rw; +{ + register struct pde *pde; + register struct pte *pte; + register int ix, cnt; + extern long Syssize; + + if (count <= 0) + return(0); + pde = (struct pde *)((u_int)u.u_procp->p_p0br + u.u_procp->p_szpt * NBPG); + ix = (addr & PD_MASK) >> PD_SHIFT; + cnt = ((addr + count + (1 << PD_SHIFT) - 1) & PD_MASK) >> PD_SHIFT; + cnt -= ix; + for (pde += ix; cnt; cnt--, pde++) + if (pde->pd_v == 0) + return(0); + ix = btop(addr-0xfe000000); + cnt = btop(addr-0xfe000000+count+NBPG-1); + if (cnt > (int)&Syssize) + return(0); + cnt -= ix; + for (pte = &Sysmap[ix]; cnt; cnt--, pte++) + if (pte->pg_v == 0 /*|| (rw == B_WRITE && pte->pg_prot == 1)*/) + return(0); + return(1); +} + +useracc(addr, count, rw) + register u_int addr; + int count, rw; +{ + register int (*func)(); + register u_int addr2; + extern int prober(), probew(); + + if (count <= 0) + return(0); + addr2 = addr; + addr += count; + func = (rw == B_READ) ? prober : probew; + do { + if ((*func)(addr2) == 0) + return(0); + addr2 = (addr2 + NBPG) & ~PGOFSET; + } while (addr2 < addr); + return(1); +} +#endif + +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 useriomap + * (a name with only slightly more meaning than "kernelmap") + */ +vmapbuf(bp) + register struct buf *bp; +{ + register int npf; + register caddr_t addr; + register long flags = bp->b_flags; + struct proc *p; + int off; + vm_offset_t kva; + register vm_offset_t pa; + + if ((flags & B_PHYS) == 0) + panic("vmapbuf"); + addr = bp->b_saveaddr = bp->b_un.b_addr; + off = (int)addr & PGOFSET; + p = bp->b_proc; + npf = btoc(round_page(bp->b_bcount + off)); + kva = kmem_alloc_wait(phys_map, ctob(npf)); + bp->b_un.b_addr = (caddr_t) (kva + off); + while (npf--) { + pa = pmap_extract(&p->p_vmspace->vm_pmap, (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. + */ +vunmapbuf(bp) + register struct buf *bp; +{ + register int npf; + register caddr_t addr = bp->b_un.b_addr; + vm_offset_t kva; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vunmapbuf"); + npf = btoc(round_page(bp->b_bcount + ((int)addr & PGOFSET))); + kva = (vm_offset_t)((int)addr & ~PGOFSET); + kmem_free_wakeup(phys_map, kva, ctob(npf)); + bp->b_un.b_addr = bp->b_saveaddr; + bp->b_saveaddr = NULL; +} + +/* + * Force reset the processor by invalidating the entire address space! + */ +cpu_reset() { + + /* force a shutdown by unmapping entire address space ! */ + bzero((caddr_t) PTD, NBPG); + + /* "good night, sweet prince .... <THUNK!>" */ + tlbflush(); + /* NOTREACHED */ +} diff --git a/sys/i386/include/_limits.h b/sys/i386/include/_limits.h new file mode 100644 index 000000000000..73474608f7cf --- /dev/null +++ b/sys/i386/include/_limits.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1988 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 7.2 (Berkeley) 6/28/90 + */ + +#define CHAR_BIT 8 /* number of bits in a char */ +#define CLK_TCK 60 /* ticks per second */ +#define MB_LEN_MAX 1 /* no multibyte characters */ + +#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */ +#define SCHAR_MAX 0x7f /* min value for a signed char */ + +#define UCHAR_MAX 0xff /* max value for an unsigned char */ +#define CHAR_MAX 0x7f /* max value for a char */ +#define CHAR_MIN (-0x7f-1) /* min value for a char */ + +#define USHRT_MAX 0xffff /* max value for an unsigned short */ +#define SHRT_MAX 0x7fff /* max value for a short */ +#define SHRT_MIN (-0x7fff-1) /* min value for a short */ + +#define UINT_MAX 0xffffffff /* max value for an unsigned int */ +#define INT_MAX 0x7fffffff /* max value for an int */ +#define INT_MIN (-0x7fffffff-1) /* min value for an int */ + +#define ULONG_MAX 0xffffffff /* max value for an unsigned long */ +#define LONG_MAX 0x7fffffff /* max value for a long */ +#define LONG_MIN (-0x7fffffff-1) /* min value for a long */ diff --git a/sys/i386/include/ansi.h b/sys/i386/include/ansi.h new file mode 100644 index 000000000000..ca677487ee65 --- /dev/null +++ b/sys/i386/include/ansi.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 1990 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 7.1 (Berkeley) 3/9/91 + */ + +#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 _SIZE_T_ + * typedef _SIZE_T_ size_t; + * #undef _SIZE_T_ + * #endif + * + * Thanks, ANSI! + */ +#define _CLOCK_T_ unsigned long /* clock() */ +#define _PTRDIFF_T_ int /* ptr1 - ptr2 */ +#define _SIZE_T_ unsigned int /* sizeof() */ +#define _TIME_T_ long /* time() */ +#define _VA_LIST_ char * /* va_list */ +#define _WCHAR_T_ unsigned short /* wchar_t */ + +#endif /* _ANSI_H_ */ diff --git a/sys/i386/include/cpu.h b/sys/i386/include/cpu.h new file mode 100644 index 000000000000..583d76c98506 --- /dev/null +++ b/sys/i386/include/cpu.h @@ -0,0 +1,108 @@ +/*- + * 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. + * + * @(#)cpu.h 5.4 (Berkeley) 5/9/91 + */ + +/* + * Definitions unique to i386 cpu support. + */ +#include "machine/frame.h" +#include "machine/segments.h" + +/* + * definitions of cpu-dependent requirements + * referenced in generic code + */ +#undef COPY_SIGCODE /* don't copy sigcode above user stack in exec */ + +/* + * function vs. inline configuration; + * these are defined to get generic functions + * rather than inline or machine-dependent implementations + */ +#define NEED_MINMAX /* need {,i,l,ul}{min,max} functions */ +#define NEED_FFS /* need ffs function */ +#define NEED_BCMP /* need bcmp function */ +#define NEED_STRLEN /* need strlen function */ + +#define cpu_exec(p) /* nothing */ + +/* + * Arguments to hardclock, softclock and gatherstats + * encapsulate the previous machine state in an opaque + * clockframe; for now, use generic intrframe. + */ +typedef struct intrframe clockframe; + +#define CLKF_USERMODE(framep) (ISPL((framep)->if_cs) == SEL_UPL) +#define CLKF_BASEPRI(framep) ((framep)->if_ppl == 0) +#define CLKF_PC(framep) ((framep)->if_eip) + +#define resettodr() /* no todr to set */ + +/* + * 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++; aston(); } + +/* + * Give a profiling tick to the current process from the softclock + * interrupt. On tahoe, request an ast to send us through trap(), + * marking the proc as needing a profiling tick. + */ +#define profile_tick(p, framep) { (p)->p_flag |= SOWEUPC; aston(); } + +/* + * Notify the current process (p) that it has a signal pending, + * process as soon as possible. + */ +#define signotify(p) aston() + +#define aston() (astpending++) + +int astpending; /* need to trap before returning to user mode */ +int want_resched; /* resched() was called */ + +/* + * Kinds of processor + */ + +#define CPU_386SX 0 +#define CPU_386 1 +#define CPU_486SX 2 +#define CPU_486 3 +#define CPU_586 4 diff --git a/sys/i386/include/cpufunc.h b/sys/i386/include/cpufunc.h new file mode 100644 index 000000000000..e3b4a8c9c052 --- /dev/null +++ b/sys/i386/include/cpufunc.h @@ -0,0 +1,82 @@ +/* + * Functions to provide access to special i386 instructions. + * XXX - bezillions more are defined in locore.s but are not declared anywhere. + */ + +#include <sys/cdefs.h> +#include <sys/types.h> + +#ifdef __GNUC__ + +static __inline int bdb(void) +{ + extern int bdb_exists; + + if (!bdb_exists) + return (0); + __asm("int $3"); + return (1); +} + +static __inline void +disable_intr(void) +{ + __asm __volatile("cli"); +} + +static __inline void +enable_intr(void) +{ + __asm __volatile("sti"); +} + +/* + * This roundabout method of returning a u_char helps stop gcc-1.40 from + * generating unnecessary movzbl's. + */ +#define inb(port) ((u_char) u_int_inb(port)) + +static __inline u_int +u_int_inb(u_int port) +{ + u_char data; + /* + * We use %%dx and not %1 here because i/o is done at %dx and not at + * %edx, while gcc-2.2.2 generates inferior code (movw instead of movl) + * if we tell it to load (u_short) port. + */ + __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); + return data; +} + +static __inline void +outb(u_int port, u_char data) +{ + register u_char al asm("ax"); + + al = data; /* help gcc-1.40's register allocator */ + __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); +} + +#else /* not __GNUC__ */ + +int bdb __P((void)); +void disable_intr __P((void)); +void enable_intr __P((void)); +u_char inb __P((u_int port)); +void outb __P((u_int port, u_int data)); /* XXX - incompat */ + +#endif /* __GNUC__ */ + +#define really_u_int int /* XXX */ +#define really_void int /* XXX */ + +void load_cr0 __P((u_int cr0)); +really_u_int rcr0 __P((void)); + +#ifdef notyet +really_void setidt __P((int idx, /*XXX*/caddr_t func, int typ, int dpl)); +#endif + +#undef really_u_int +#undef really_void diff --git a/sys/i386/include/db_machdep.h b/sys/i386/include/db_machdep.h new file mode 100644 index 000000000000..8e37eec43fbc --- /dev/null +++ b/sys/i386/include/db_machdep.h @@ -0,0 +1,154 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 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. + */ +/* + * HISTORY + * $Log: db_machdep.h,v $ + * Revision 2.8 92/02/19 15:07:56 elf + * Added db_thread_fp_used. + * [92/02/19 rpd] + * + * Revision 2.7 91/10/09 16:06:28 af + * Revision 2.6.3.1 91/10/05 13:10:32 jeffreyh + * Added access and task name macros. + * [91/08/29 tak] + * + * Revision 2.6.3.1 91/10/05 13:10:32 jeffreyh + * Added access and task name macros. + * [91/08/29 tak] + * + * Revision 2.6 91/05/14 16:05:58 mrt + * Correcting copyright + * + * Revision 2.5 91/02/05 17:11:17 mrt + * Changed to new Mach copyright + * [91/02/01 17:31:24 mrt] + * + * Revision 2.4 91/01/08 15:10:16 rpd + * Added dummy inst_load/inst_store macros. + * [90/12/11 rpd] + * + * Revision 2.3 90/10/25 14:44:49 rwd + * Added watchpoint support. + * [90/10/18 rpd] + * + * Revision 2.2 90/08/27 21:56:15 dbg + * Created. + * [90/07/25 dbg] + * + */ + +#ifndef _I386_DB_MACHDEP_H_ +#define _I386_DB_MACHDEP_H_ + +/* + * Machine-dependent defines for new kernel debugger. + */ + + +/* #include <mach/i386/vm_types.h> */ +/* #include <mach/i386/vm_param.h> */ +#include <vm/vm_prot.h> +#include <vm/vm_param.h> +#include <vm/vm_inherit.h> +#include <vm/lock.h> +/* #include <i386/thread.h> */ /* for thread_status */ +#include <machine/frame.h> /* for struct trapframe */ +/* #include <i386/eflags.h> */ +#include <machine/eflags.h> /* from Mach... */ +/* #include <i386/trap.h> */ +#include <machine/trap.h> + +#define i386_saved_state trapframe +/* end of mangling */ + +typedef vm_offset_t db_addr_t; /* address - unsigned */ +typedef int db_expr_t; /* expression - signed */ + +typedef struct i386_saved_state db_regs_t; +db_regs_t ddb_regs; /* register state */ +#define DDB_REGS (&ddb_regs) + +#define PC_REGS(regs) ((db_addr_t)(regs)->tf_eip) + +#define BKPT_INST 0xcc /* breakpoint instruction */ +#define BKPT_SIZE (1) /* size of breakpoint inst */ +#define BKPT_SET(inst) (BKPT_INST) + +#define FIXUP_PC_AFTER_BREAK ddb_regs.tf_eip -= 1; + +#define db_clear_single_step(regs) ((regs)->tf_eflags &= ~EFL_TF) +#define db_set_single_step(regs) ((regs)->tf_eflags |= EFL_TF) + +/* #define IS_BREAKPOINT_TRAP(type, code) ((type) == T_INT3) */ +/* #define IS_WATCHPOINT_TRAP(type, code) ((type) == T_WATCHPOINT) */ +/* using the 386bsd values, rather than the Mach ones: */ +#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT) +#define IS_WATCHPOINT_TRAP(type, code) ((type) == T_KDBTRAP) + +#define I_CALL 0xe8 +#define I_CALLI 0xff +#define I_RET 0xc3 +#define I_IRET 0xcf + +#define inst_trap_return(ins) (((ins)&0xff) == I_IRET) +#define inst_return(ins) (((ins)&0xff) == I_RET) +#define inst_call(ins) (((ins)&0xff) == I_CALL || \ + (((ins)&0xff) == I_CALLI && \ + ((ins)&0x3800) == 0x1000)) +#define inst_load(ins) 0 +#define inst_store(ins) 0 + +/* access capability and access macros */ + +#define DB_ACCESS_LEVEL 2 /* access any space */ +#define DB_CHECK_ACCESS(addr,size,task) \ + db_check_access(addr,size,task) +#define DB_PHYS_EQ(task1,addr1,task2,addr2) \ + db_phys_eq(task1,addr1,task2,addr2) +#define DB_VALID_KERN_ADDR(addr) \ + ((addr) >= VM_MIN_KERNEL_ADDRESS && \ + (addr) < VM_MAX_KERNEL_ADDRESS) +#define DB_VALID_ADDRESS(addr,user) \ + ((!(user) && DB_VALID_KERN_ADDR(addr)) || \ + ((user) && (addr) < VM_MIN_KERNEL_ADDRESS)) + +boolean_t db_check_access(/* vm_offset_t, int, task_t */); +boolean_t db_phys_eq(/* task_t, vm_offset_t, task_t, vm_offset_t */); + +/* macros for printing OS server dependent task name */ + +#define DB_TASK_NAME(task) db_task_name(task) +#define DB_TASK_NAME_TITLE "COMMAND " +#define DB_TASK_NAME_LEN 23 +#define DB_NULL_TASK_NAME "? " + +void db_task_name(/* task_t */); + +/* macro for checking if a thread has used floating-point */ + +#define db_thread_fp_used(thread) ((thread)->pcb->ims.ifps != 0) + +#endif /* _I386_DB_MACHDEP_H_ */ diff --git a/sys/i386/include/dkio.h b/sys/i386/include/dkio.h new file mode 100644 index 000000000000..1bb06c99bda8 --- /dev/null +++ b/sys/i386/include/dkio.h @@ -0,0 +1,48 @@ +/*- + * 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. + * + * @(#)dkio.h 5.2 (Berkeley) 1/18/91 + */ + +/* + * Structures and definitions for disk io control commands + * + * THIS WHOLE AREA NEEDS MORE THOUGHT. FOR NOW JUST IMPLEMENT + * ENOUGH TO READ AND WRITE HEADERS ON MASSBUS DISKS. EVENTUALLY + * SHOULD BE ABLE TO DETERMINE DRIVE TYPE AND DO OTHER GOOD STUFF. + */ + +/* disk io control commands */ +#define DKIOCHDR _IO(d, 1) /* next I/O will read/write header */ diff --git a/sys/i386/include/eflags.h b/sys/i386/include/eflags.h new file mode 100644 index 000000000000..84f32757ec7c --- /dev/null +++ b/sys/i386/include/eflags.h @@ -0,0 +1,67 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: eflags.h,v $ + * Revision 2.4 91/05/14 16:06:35 mrt + * Correcting copyright + * + * Revision 2.3 91/02/05 17:11:26 mrt + * Changed to new Mach copyright + * [91/02/01 17:31:41 mrt] + * + * Revision 2.2 90/05/03 15:25:03 dbg + * Created. + * [90/02/08 dbg] + * + */ + +#ifndef _I386_EFLAGS_H_ +#define _I386_EFLAGS_H_ + +/* + * i386 flags register + */ +#define EFL_CF 0x00000001 /* carry */ +#define EFL_PF 0x00000004 /* parity of low 8 bits */ +#define EFL_AF 0x00000010 /* carry out of bit 3 */ +#define EFL_ZF 0x00000040 /* zero */ +#define EFL_SF 0x00000080 /* sign */ +#define EFL_TF 0x00000100 /* trace trap */ +#define EFL_IF 0x00000200 /* interrupt enable */ +#define EFL_DF 0x00000400 /* direction */ +#define EFL_OF 0x00000800 /* overflow */ +#define EFL_IOPL 0x00003000 /* IO privilege level: */ +#define EFL_IOPL_KERNEL 0x00000000 /* kernel */ +#define EFL_IOPL_USER 0x00003000 /* user */ +#define EFL_NT 0x00004000 /* nested task */ +#define EFL_RF 0x00010000 /* resume without tracing */ +#define EFL_VM 0x00020000 /* virtual 8086 mode */ + +#define EFL_USER_SET (EFL_IF) +#define EFL_USER_CLEAR (EFL_IOPL|EFL_NT|EFL_RF) + +#endif _I386_EFLAGS_H_ diff --git a/sys/i386/include/endian.h b/sys/i386/include/endian.h new file mode 100644 index 000000000000..404bf4932ed4 --- /dev/null +++ b/sys/i386/include/endian.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1987, 1991 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 7.8 (Berkeley) 4/3/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00093 + * -------------------- ----- ---------------------- + * + * 27 Feb 93 Charles Hannum Better byte-swapping macros for + * i386/i486. + */ + +/* + * 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 + +#ifndef KERNEL +#include <sys/cdefs.h> +#endif + +#define __word_swap_long(x) \ +({ register u_long X = (x); \ + asm ("rorl $16, %1" \ + : "=r" (X) \ + : "0" (X)); \ + X; }) +#if __GNUC__ >= 2 +#define __byte_swap_long(x) \ +({ register u_long X = (x); \ + asm ("xchgb %h1, %b1\n\trorl $16, %1\n\txchgb %h1, %b1" \ + : "=q" (X) \ + : "0" (X)); \ + X; }) +#define __byte_swap_word(x) \ +({ register u_short X = (x); \ + asm ("xchgb %h1, %b1" \ + : "=q" (X) \ + : "0" (X)); \ + X; }) +#else /* __GNUC__ >= 2 */ +#define __byte_swap_long(x) \ +({ register u_long X = (x); \ + asm ("rorw $8, %w1\n\trorl $16, %1\n\trorw $8, %w1" \ + : "=r" (X) \ + : "0" (X)); \ + X; }) +#define __byte_swap_word(x) \ +({ register u_short X = (x); \ + asm ("rorw $8, %w1" \ + : "=r" (X) \ + : "0" (X)); \ + X; }) +#endif /* __GNUC__ >= 2 */ + +/* + * 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 __byte_swap_long +#define ntohs __byte_swap_word +#define htonl __byte_swap_long +#define htons __byte_swap_word + +#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 diff --git a/sys/i386/include/float.h b/sys/i386/include/float.h new file mode 100644 index 000000000000..edfe0d929199 --- /dev/null +++ b/sys/i386/include/float.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1989 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 7.1 (Berkeley) 5/8/90 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00086 + * -------------------- ----- ---------------------- + * + * 27 Feb 93 Handel/da Silva/Poirot Adjust value for MAX_DOUBLE + */ + +#define FLT_RADIX 2 /* b */ +#define FLT_ROUNDS 1 /* FP addition rounds to nearest */ + +#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.797693134862315E+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 diff --git a/sys/i386/include/frame.h b/sys/i386/include/frame.h new file mode 100644 index 000000000000..4dbabd1935ce --- /dev/null +++ b/sys/i386/include/frame.h @@ -0,0 +1,116 @@ +/*- + * 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. + * + * @(#)frame.h 5.2 (Berkeley) 1/18/91 + */ + +/* + * System stack frames. + */ + +/* + * Exception/Trap Stack Frame + */ + +struct trapframe { + int tf_es; + int tf_ds; + int tf_edi; + int tf_esi; + int tf_ebp; + int tf_isp; + int tf_ebx; + int tf_edx; + int tf_ecx; + int tf_eax; + int tf_trapno; + /* below portion defined in 386 hardware */ + int tf_err; + int tf_eip; + int tf_cs; + int tf_eflags; + /* below only when transitting rings (e.g. user to kernel) */ + int tf_esp; + int tf_ss; +}; + +/* Interrupt stack frame */ + +struct intrframe { + int if_vec; + int if_ppl; + int if_es; + int if_ds; + int if_edi; + int if_esi; + int if_ebp; + int :32; + int if_ebx; + int if_edx; + int if_ecx; + int if_eax; + int :32; /* for compat with trap frame - trapno */ + int :32; /* for compat with trap frame - err */ + /* below portion defined in 386 hardware */ + int if_eip; + int if_cs; + int if_eflags; + /* below only when transitting rings (e.g. user to kernel) */ + int if_esp; + int if_ss; +}; + +/* + * Call Gate/System Call Stack Frame + */ + +struct syscframe { + int sf_edi; + int sf_esi; + int sf_ebp; + int :32; /* redundant save of isp */ + int sf_ebx; + int sf_edx; + int sf_ecx; + int sf_eax; + int sf_eflags; + /* below portion defined in 386 hardware */ +/* int sf_args[N]; /* if call gate copy args enabled!*/ + int sf_eip; + int sf_cs; + /* below only when transitting rings (e.g. user to kernel) */ + int sf_esp; + int sf_ss; +}; diff --git a/sys/i386/include/limits.h b/sys/i386/include/limits.h new file mode 100644 index 000000000000..73474608f7cf --- /dev/null +++ b/sys/i386/include/limits.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1988 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 7.2 (Berkeley) 6/28/90 + */ + +#define CHAR_BIT 8 /* number of bits in a char */ +#define CLK_TCK 60 /* ticks per second */ +#define MB_LEN_MAX 1 /* no multibyte characters */ + +#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */ +#define SCHAR_MAX 0x7f /* min value for a signed char */ + +#define UCHAR_MAX 0xff /* max value for an unsigned char */ +#define CHAR_MAX 0x7f /* max value for a char */ +#define CHAR_MIN (-0x7f-1) /* min value for a char */ + +#define USHRT_MAX 0xffff /* max value for an unsigned short */ +#define SHRT_MAX 0x7fff /* max value for a short */ +#define SHRT_MIN (-0x7fff-1) /* min value for a short */ + +#define UINT_MAX 0xffffffff /* max value for an unsigned int */ +#define INT_MAX 0x7fffffff /* max value for an int */ +#define INT_MIN (-0x7fffffff-1) /* min value for an int */ + +#define ULONG_MAX 0xffffffff /* max value for an unsigned long */ +#define LONG_MAX 0x7fffffff /* max value for a long */ +#define LONG_MIN (-0x7fffffff-1) /* min value for a long */ diff --git a/sys/i386/include/mtpr.h b/sys/i386/include/mtpr.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/sys/i386/include/mtpr.h diff --git a/sys/i386/include/npx.h b/sys/i386/include/npx.h new file mode 100644 index 000000000000..134e0c12aee8 --- /dev/null +++ b/sys/i386/include/npx.h @@ -0,0 +1,146 @@ +/*- + * 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. + * + * @(#)npx.h 5.3 (Berkeley) 1/18/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Bruce Evans New npx-0.5 code + * + */ + +/* + * 287/387 NPX Coprocessor Data Structures and Constants + * W. Jolitz 1/90 + */ + +#ifndef ___NPX87___ +#define ___NPX87___ + +/* Environment information of floating point unit */ +struct env87 { + long en_cw; /* control word (16bits) */ + long en_sw; /* status word (16bits) */ + long en_tw; /* tag word (16bits) */ + long en_fip; /* floating point instruction pointer */ + u_short en_fcs; /* floating code segment selector */ + u_short en_opcode; /* opcode last executed (11 bits ) */ + long en_foo; /* floating operand offset */ + long en_fos; /* floating operand segment selector */ +}; + +/* Contents of each floating point accumulator */ +struct fpacc87 { +#ifdef dontdef /* too unportable */ + u_long fp_mantlo; /* mantissa low (31:0) */ + u_long fp_manthi; /* mantissa high (63:32) */ + int fp_exp:15; /* exponent */ + int fp_sgn:1; /* mantissa sign */ +#else + u_char fp_bytes[10]; +#endif +}; + +/* Floating point context */ +struct save87 { + struct env87 sv_env; /* floating point control/status */ + struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */ +#ifndef dontdef + u_long sv_ex_sw; /* status word for last exception (was pad) */ + u_long sv_ex_tw; /* tag word for last exception (was pad) */ + u_char sv_pad[8 * 2 - 2 * 4]; /* bogus historical padding */ +#endif +}; + +/* Cyrix EMC memory - mapped coprocessor context switch information */ +struct emcsts { + long em_msw; /* memory mapped status register when swtched */ + long em_tar; /* memory mapped temp A register when swtched */ + long em_dl; /* memory mapped D low register when swtched */ +}; + +/* Intel prefers long real (53 bit) precision */ +#define __iBCS_NPXCW__ 0x262 +/* wfj prefers temporary real (64 bit) precision */ +#define __386BSD_NPXCW__ 0x362 +/* + * bde prefers 53 bit precision and all exceptions masked. + * + * The standard control word from finit is 0x37F, giving: + * + * round to nearest + * 64-bit precision + * all exceptions masked. + * + * Now I want: + * + * affine mode for 287's (if they work at all) (1 in bitfield 1<<12) + * 53-bit precision (2 in bitfield 3<<8) + * overflow exception unmasked (0 in bitfield 1<<3) + * zero divide exception unmasked (0 in bitfield 1<<2) + * invalid-operand exception unmasked (0 in bitfield 1<<0). + * + * 64-bit precision often gives bad results with high level languages + * because it makes the results of calculations depend on whether + * intermediate values are stored in memory or in FPU registers. + * + * The "Intel" and wfj control words have: + * + * underflow exception unmasked (0 in bitfield 1<<4) + * + * but that causes an unexpected exception in the test program 'paranoia' + * and makes denormals useless (DBL_MIN / 2 underflows). It doesn't make + * a lot of sense to trap underflow without trapping denormals. + * + * Later I will want the IEEE default of all exceptions masked. See the + * 0.0 math manpage for why this is better. The 0.1 math manpage is empty. + */ +#define __BDE_NPXCW__ 0x1272 +#define __BETTER_BDE_NPXCW__ 0x127f + +#ifdef __BROKEN_NPXCW__ +#ifdef __386BSD__ +#define __INITIAL_NPXCW__ __386BSD_NPXCW__ +#else +#define __INITIAL_NPXCW__ __iBCS_NPXCW__ +#endif +#else +#define __INITIAL_NPXCW__ __BDE_NPXCW__ +#endif + +#endif ___NPX87___ diff --git a/sys/i386/include/param.h b/sys/i386/include/param.h new file mode 100644 index 000000000000..1ee217a6eefb --- /dev/null +++ b/sys/i386/include/param.h @@ -0,0 +1,164 @@ +/*- + * 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. + * + * @(#)param.h 5.8 (Berkeley) 6/28/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 2 00166 + * -------------------- ----- ---------------------- + * + * 08 Apr 93 Andrew Herbert Fixes for kmem_alloc panics + * Rodney W. Grimes Tuneable mbuf sizes + * 04 Jun 93 Rodney W. Grimes Change default mbuf size to 2048 via + * MCLSHIFT. + */ + +/* + * Machine dependent constants for Intel 386. + */ + +#define MACHINE "i386" + +/* + * 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 ALIGN(p) (((u_int)(p) + (sizeof(int) - 1)) &~ (sizeof(int) - 1)) + +#define NBPG 4096 /* bytes/page */ +#define PGOFSET (NBPG-1) /* byte offset into page */ +#define PGSHIFT 12 /* LOG2(NBPG) */ +#define NPTEPG (NBPG/(sizeof (struct pte))) + +#define NBPDR (1024*NBPG) /* bytes/page dir */ +#define PDROFSET (NBPDR-1) /* byte offset into page dir */ +#define PDRSHIFT 22 /* LOG2(NBPDR) */ + +#define KERNBASE 0xFE000000 /* start of kernel virtual */ +#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 */ + +/* + * 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. + */ +#ifndef MSIZE +#define MSIZE 128 /* size of an mbuf */ +#endif /* MSIZE */ + +#ifndef MCLSHIFT +#define MCLSHIFT 11 /* convert bytes to m_buf clusters */ +#endif /* MCLSHIFT */ +#define MCLBYTES (1 << MCLSHIFT) /* size of an m_buf cluster */ +#define MCLOFSET (MCLBYTES - 1) /* offset within an m_buf cluster */ + +#ifndef NMBCLUSTERS +#ifdef GATEWAY +#define NMBCLUSTERS 512 /* map size, max cluster allocation */ +#else +#define NMBCLUSTERS 256 /* map size, max cluster allocation */ +#endif /* GATEWAY */ +#endif /* NMBCLUSTERS */ + +/* + * Size of kernel malloc arena in CLBYTES-sized logical pages + */ +#ifndef NKMEMCLUSTERS +#define NKMEMCLUSTERS (3072*1024/CLBYTES) +#endif +/* + * Some macros for units conversion + */ +/* Core clicks (4096 bytes) to segments and vice versa */ +#define ctos(x) (x) +#define stoc(x) (x) + +/* Core clicks (4096 bytes) to disk blocks */ +#define ctod(x) ((x)<<(PGSHIFT-DEV_BSHIFT)) +#define dtoc(x) ((x)>>(PGSHIFT-DEV_BSHIFT)) +#define dtob(x) ((x)<<DEV_BSHIFT) + +/* clicks to bytes */ +#define ctob(x) ((x)<<PGSHIFT) + +/* bytes to clicks */ +#define btoc(x) (((unsigned)(x)+(NBPG-1))>>PGSHIFT) + +#define btodb(bytes) /* calculates (bytes / DEV_BSIZE) */ \ + ((unsigned)(bytes) >> DEV_BSHIFT) +#define dbtob(db) /* calculates (db * DEV_BSIZE) */ \ + ((unsigned)(db) << DEV_BSHIFT) + +/* + * Map a ``block device block'' to a file system block. + * This should be device dependent, and will be if we + * add an entry to cdevsw/bdevsw for that purpose. + * For now though just use DEV_BSIZE. + */ +#define bdbtofsb(bn) ((bn) / (BLKDEV_IOSIZE/DEV_BSIZE)) + +/* + * Mach derived conversion macros + */ +#define i386_round_pdr(x) ((((unsigned)(x)) + NBPDR - 1) & ~(NBPDR-1)) +#define i386_trunc_pdr(x) ((unsigned)(x) & ~(NBPDR-1)) +#define i386_round_page(x) ((((unsigned)(x)) + NBPG - 1) & ~(NBPG-1)) +#define i386_trunc_page(x) ((unsigned)(x) & ~(NBPG-1)) +#define i386_btod(x) ((unsigned)(x) >> PDRSHIFT) +#define i386_dtob(x) ((unsigned)(x) << PDRSHIFT) +#define i386_btop(x) ((unsigned)(x) >> PGSHIFT) +#define i386_ptob(x) ((unsigned)(x) << PGSHIFT) + +#ifndef KERNEL +#define DELAY(n) { volatile int N = (n); while (--N > 0); } +#endif diff --git a/sys/i386/include/pc/display.h b/sys/i386/include/pc/display.h new file mode 100644 index 000000000000..cab46e44e881 --- /dev/null +++ b/sys/i386/include/pc/display.h @@ -0,0 +1,43 @@ +/* + * 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 + +/* 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 + +/* 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/i386/include/pc/msdos.h b/sys/i386/include/pc/msdos.h new file mode 100644 index 000000000000..8d1eb7bfd52d --- /dev/null +++ b/sys/i386/include/pc/msdos.h @@ -0,0 +1,63 @@ +/* + * msdos common header file + * [obtained from mtools -wfj] + * how to decipher DOS disk structures in coexisting with DOS + */ + +#define MSECTOR_SIZE 512 /* MSDOS sector size in bytes */ +#define MDIR_SIZE 32 /* MSDOS directory size in bytes */ +#define MAX_CLUSTER 8192 /* largest cluster size */ +#define MAX_PATH 128 /* largest MSDOS path length */ +#define MAX_DIR_SECS 64 /* largest directory (in sectors) */ + +#define NEW 1 +#define OLD 0 + +struct directory { + unsigned char name[8]; /* file name */ + unsigned char ext[3]; /* file extension */ + unsigned char attr; /* attribute byte */ + unsigned char reserved[10]; /* ?? */ + unsigned char time[2]; /* time stamp */ + unsigned char date[2]; /* date stamp */ + unsigned char start[2]; /* starting cluster number */ + unsigned char size[4]; /* size of the file */ +}; + +struct bootsector { + unsigned char jump[3]; /* Jump to boot code */ + unsigned char banner[8]; /* OEM name & version */ + unsigned char secsiz[2]; /* Bytes per sector hopefully 512 */ + unsigned char clsiz; /* Cluster size in sectors */ + unsigned char nrsvsect[2]; /* Number of reserved (boot) sectors */ + unsigned char nfat; /* Number of FAT tables hopefully 2 */ + unsigned char dirents[2]; /* Number of directory slots */ + unsigned char psect[2]; /* Total sectors on disk */ + unsigned char descr; /* Media descriptor=first byte of FAT */ + unsigned char fatlen[2]; /* Sectors in FAT */ + unsigned char nsect[2]; /* Sectors/track */ + unsigned char nheads[2]; /* Heads */ + unsigned char nhs[4]; /* number of hidden sectors */ + unsigned char bigsect[4]; /* big total sectors */ + unsigned char junk[476]; /* who cares? */ +}; + +/* DOS partition table -- located in boot block */ + +#define DOSBBSECTOR 0 /* DOS boot block relative sector number */ +#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 */ +#define DOSPTYP_386BSD 0xa5 /* 386BSD partition type */ + 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]; diff --git a/sys/i386/include/pcb.h b/sys/i386/include/pcb.h new file mode 100644 index 000000000000..92bd810ca0df --- /dev/null +++ b/sys/i386/include/pcb.h @@ -0,0 +1,87 @@ +/*- + * 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. + * + * @(#)pcb.h 5.10 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Bruce Evans New npx-0.5 code + * + */ + +/* + * Intel 386 process control block + */ +#include "machine/tss.h" +#include "machine/npx.h" + +struct pcb { + struct i386tss pcb_tss; +#define pcb_ksp pcb_tss.tss_esp0 +#define pcb_ptd pcb_tss.tss_cr3 +#define pcb_cr3 pcb_ptd +#define pcb_pc pcb_tss.tss_eip +#define pcb_psl pcb_tss.tss_eflags +#define pcb_usp pcb_tss.tss_esp +#define pcb_fp pcb_tss.tss_ebp +#ifdef notyet + u_char pcb_iomap[NPORT/sizeof(u_char)]; /* i/o port bitmap */ +#endif + struct save87 pcb_savefpu; /* floating point state for 287/387 */ + struct emcsts pcb_saveemc; /* Cyrix EMC state */ +/* + * Software pcb (extension) + */ + int pcb_flags; +#ifdef notused +#define FP_WASUSED 0x01 /* process has used fltng pnt hardware */ +#define FP_NEEDSSAVE 0x02 /* ... that needs save on next context switch */ +#define FP_NEEDSRESTORE 0x04 /* ... that needs restore on next DNA fault */ +#endif +#define FP_USESEMC 0x08 /* process uses EMC memory-mapped mode */ +#define FM_TRAP 0x10 /* process entered kernel on a trap frame */ +#define FP_SOFTFP 0x20 /* process using software fltng pnt emulator */ + short pcb_iml; /* interrupt mask level */ + caddr_t pcb_onfault; /* copyin/out fault recovery */ + long pcb_sigc[8]; /* XXX signal code trampoline */ + int pcb_cmap2; /* XXX temporary PTE - will prefault instead */ +}; + +#ifdef KERNEL +struct pcb *curpcb; /* our current running pcb */ +#endif diff --git a/sys/i386/include/pio.h b/sys/i386/include/pio.h new file mode 100644 index 000000000000..553a97a45370 --- /dev/null +++ b/sys/i386/include/pio.h @@ -0,0 +1,75 @@ +/* + * Mach Operating System + * Copyright (c) 1990 Carnegie-Mellon University + * All rights reserved. The CMU software License Agreement specifies + * the terms and conditions for use and redistribution. + */ +/* + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00158 + * -------------------- ----- ---------------------- + * + * 27 May 93 Rodney W. Grimes Added #ifndef around inb so that the + * clash with cpufunc.h does not cause + * a compile warning.. this is a hack. + * All of this needs cleaned up at 0.1.5 + * + * HISTORY + * $Log: pio.h,v $ + * Revision 1.1 1992/05/27 00:48:30 balsup + * machkern/cor merge + * + * Revision 1.1 1991/10/10 20:11:39 balsup + * Initial revision + * + * Revision 2.2 91/04/02 11:52:29 mbj + * [90/08/14 mg32] + * + * Now we know how types are factor in. + * Cleaned up a bunch: eliminated ({ for output and flushed unused + * output variables. + * [90/08/14 rvb] + * + * This is how its done in gcc: + * Created. + * [90/03/26 rvb] + * + */ + + +#define inl(y) \ +({ unsigned long _tmp__; \ + asm volatile("inl %1, %0" : "=a" (_tmp__) : "d" ((unsigned short)(y))); \ + _tmp__; }) + +#define inw(y) \ +({ unsigned short _tmp__; \ + asm volatile(".byte 0x66; inl %1, %0" : "=a" (_tmp__) : "d" ((unsigned short)(y))); \ + _tmp__; }) + +/* + * only do this if it has not already be defined.. this is a crock for the + * patch kit for right now. Need to clean up all the inx, outx stuff for + * 0.1.5 to use 1 common header file, that has Bruces fast mode inb/outb + * stuff in it. Rgrimes 5/27/93 + */ +#ifndef inb +#define inb(y) \ +({ unsigned char _tmp__; \ + asm volatile("inb %1, %0" : "=a" (_tmp__) : "d" ((unsigned short)(y))); \ + _tmp__; }) +#endif + + +#define outl(x, y) \ +{ asm volatile("outl %0, %1" : : "a" (y) , "d" ((unsigned short)(x))); } + + +#define outw(x, y) \ +{asm volatile(".byte 0x66; outl %0, %1" : : "a" ((unsigned short)(y)) , "d" ((unsigned short)(x))); } + + +#define outb(x, y) \ +{ asm volatile("outb %0, %1" : : "a" ((unsigned char)(y)) , "d" ((unsigned short)(x))); } diff --git a/sys/i386/include/pmap.h b/sys/i386/include/pmap.h new file mode 100644 index 000000000000..2eff22fa229f --- /dev/null +++ b/sys/i386/include/pmap.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) 1991 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 William Jolitz of UUNET Technologies 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. + * + * @(#)pmap.h 7.4 (Berkeley) 5/12/91 + */ + +/* + * Derived from hp300 version by Mike Hibler, this version by William + * Jolitz uses a recursive map [a pde points to the page directory] to + * map the page tables using the pagetables themselves. This is done to + * reduce the impact on kernel virtual memory for lots of sparse address + * space, and to reduce the cost of memory to each process. + * + * from hp300: @(#)pmap.h 7.2 (Berkeley) 12/16/90 + */ + +#ifndef _PMAP_MACHINE_ +#define _PMAP_MACHINE_ 1 + +/* + * 386 page table entry and page table directory + * W.Jolitz, 8/89 + */ + +struct pde +{ +unsigned int + pd_v:1, /* valid bit */ + pd_prot:2, /* access control */ + pd_mbz1:2, /* reserved, must be zero */ + pd_u:1, /* hardware maintained 'used' bit */ + :1, /* not used */ + pd_mbz2:2, /* reserved, must be zero */ + :3, /* reserved for software */ + pd_pfnum:20; /* physical page frame number of pte's*/ +}; + +#define PD_MASK 0xffc00000 /* page directory address bits */ +#define PT_MASK 0x003ff000 /* page table address bits */ +#define PD_SHIFT 22 /* page directory address shift */ +#define PG_SHIFT 12 /* page table address shift */ + +struct pte +{ +unsigned int + pg_v:1, /* valid bit */ + pg_prot:2, /* access control */ + pg_mbz1:2, /* reserved, must be zero */ + pg_u:1, /* hardware maintained 'used' bit */ + pg_m:1, /* hardware maintained modified bit */ + pg_mbz2:2, /* reserved, must be zero */ + pg_w:1, /* software, wired down page */ + :1, /* software (unused) */ + pg_nc:1, /* 'uncacheable page' bit */ + pg_pfnum:20; /* physical page frame number */ +}; + +#define PG_V 0x00000001 +#define PG_RO 0x00000000 +#define PG_RW 0x00000002 +#define PG_u 0x00000004 +#define PG_PROT 0x00000006 /* all protection bits . */ +#define PG_W 0x00000200 +#define PG_N 0x00000800 /* Non-cacheable */ +#define PG_M 0x00000040 +#define PG_U 0x00000020 +#define PG_FRAME 0xfffff000 + +#define PG_NOACC 0 +#define PG_KR 0x00000000 +#define PG_KW 0x00000002 +#define PG_URKR 0x00000004 +#define PG_URKW 0x00000004 +#define PG_UW 0x00000006 + +/* Garbage for current bastardized pager that assumes a hp300 */ +#define PG_NV 0 +#define PG_CI 0 +/* + * Page Protection Exception bits + */ + +#define PGEX_P 0x01 /* Protection violation vs. not present */ +#define PGEX_W 0x02 /* during a Write cycle */ +#define PGEX_U 0x04 /* access from User mode (UPL) */ + +typedef struct pde pd_entry_t; /* page directory entry */ +typedef struct pte pt_entry_t; /* Mach page table entry */ + +/* + * One page directory, shared between + * kernel and user modes. + */ +#define I386_PAGE_SIZE NBPG +#define I386_PDR_SIZE NBPDR + +#define I386_KPDES 8 /* KPT page directory size */ +#define I386_UPDES NBPDR/sizeof(struct pde)-8 /* UPT page directory size */ + +#define UPTDI 0x3f6 /* ptd entry for u./kernel&user stack */ +#define PTDPTDI 0x3f7 /* ptd entry that points to ptd! */ +#define KPTDI_FIRST 0x3f8 /* start of kernel virtual pde's */ +#define KPTDI_LAST 0x3fA /* last of kernel virtual pde's */ + +/* + * Address of current and alternate address space page table maps + * and directories. + */ +#ifdef KERNEL +extern struct pte PTmap[], APTmap[], Upte; +extern struct pde PTD[], APTD[], PTDpde, APTDpde, Upde; +extern pt_entry_t *Sysmap; + +extern int IdlePTD; /* physical address of "Idle" state directory */ +#endif + +/* + * virtual address to page table entry and + * to physical address. Likewise for alternate address space. + * Note: these work recursively, thus vtopte of a pte will give + * the corresponding pde that in turn maps it. + */ +#define vtopte(va) (PTmap + i386_btop(va)) +#define kvtopte(va) vtopte(va) +#define ptetov(pt) (i386_ptob(pt - PTmap)) +#define vtophys(va) (i386_ptob(vtopte(va)->pg_pfnum) | ((int)(va) & PGOFSET)) +#define ispt(va) ((va) >= UPT_MIN_ADDRESS && (va) <= KPT_MAX_ADDRESS) + +#define avtopte(va) (APTmap + i386_btop(va)) +#define ptetoav(pt) (i386_ptob(pt - APTmap)) +#define avtophys(va) (i386_ptob(avtopte(va)->pg_pfnum) | ((int)(va) & PGOFSET)) + +/* + * macros to generate page directory/table indicies + */ + +#define pdei(va) (((va)&PD_MASK)>>PD_SHIFT) +#define ptei(va) (((va)&PT_MASK)>>PG_SHIFT) + +/* + * Pmap stuff + */ + +struct pmap { + pd_entry_t *pm_pdir; /* KVA of page directory */ + boolean_t pm_pdchanged; /* pdir changed */ + short pm_dref; /* page directory ref count */ + short pm_count; /* pmap reference count */ + simple_lock_data_t pm_lock; /* lock on pmap */ + struct pmap_statistics pm_stats; /* pmap statistics */ + long pm_ptpages; /* more stats: PT pages */ +}; + +typedef struct pmap *pmap_t; + +#ifdef KERNEL +extern pmap_t kernel_pmap; +#endif + +/* + * Macros for speed + */ +#define PMAP_ACTIVATE(pmapp, pcbp) \ + if ((pmapp) != NULL /*&& (pmapp)->pm_pdchanged */) { \ + (pcbp)->pcb_cr3 = \ + pmap_extract(kernel_pmap, (pmapp)->pm_pdir); \ + if ((pmapp) == &curproc->p_vmspace->vm_pmap) \ + load_cr3((pcbp)->pcb_cr3); \ + (pmapp)->pm_pdchanged = FALSE; \ + } + +#define PMAP_DEACTIVATE(pmapp, pcbp) + +/* + * 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. + */ +typedef struct pv_entry { + struct pv_entry *pv_next; /* next pv_entry */ + pmap_t pv_pmap; /* pmap where mapping lies */ + vm_offset_t pv_va; /* virtual address for mapping */ + int pv_flags; /* flags */ +} *pv_entry_t; + +#define PV_ENTRY_NULL ((pv_entry_t) 0) + +#define PV_CI 0x01 /* all entries must be cache inhibited */ +#define PV_PTPAGE 0x02 /* entry maps a page table page */ + +#ifdef KERNEL + +pv_entry_t pv_table; /* array of entries, one per page */ + +#define pa_index(pa) atop(pa - vm_first_phys) +#define pa_to_pvh(pa) (&pv_table[pa_index(pa)]) + +#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) + +#endif KERNEL + +#endif _PMAP_MACHINE_ diff --git a/sys/i386/include/proc.h b/sys/i386/include/proc.h new file mode 100644 index 000000000000..02f3c01ac3e8 --- /dev/null +++ b/sys/i386/include/proc.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1991 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. + * + * @(#)proc.h 7.1 (Berkeley) 5/15/91 + */ + +/* + * Machine-dependent part of the proc structure for hp300. + */ +struct mdproc { + int md_flags; /* machine-dependent flags */ +#ifdef notyet + int *p_regs; /* registers on current frame */ +#endif +}; + +/* md_flags */ +#define MDP_AST 0x0001 /* async trap pending */ diff --git a/sys/i386/include/psl.h b/sys/i386/include/psl.h new file mode 100644 index 000000000000..aee73ed25ce2 --- /dev/null +++ b/sys/i386/include/psl.h @@ -0,0 +1,60 @@ +/*- + * 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. + * + * @(#)psl.h 5.2 (Berkeley) 1/18/91 + */ + +/* + * 386 processor status longword. + */ +#define PSL_C 0x00000001 /* carry bit */ +#define PSL_PF 0x00000004 /* parity bit */ +#define PSL_AF 0x00000010 /* bcd carry bit */ +#define PSL_Z 0x00000040 /* zero bit */ +#define PSL_N 0x00000080 /* negative bit */ +#define PSL_T 0x00000100 /* trace enable bit */ +#define PSL_I 0x00000200 /* interrupt enable bit */ +#define PSL_D 0x00000400 /* string instruction direction bit */ +#define PSL_V 0x00000800 /* overflow bit */ +#define PSL_IOPL 0x00003000 /* i/o priviledge level enable */ +#define PSL_NT 0x00004000 /* nested task bit */ +#define PSL_RF 0x00010000 /* restart flag bit */ +#define PSL_VM 0x00020000 /* virtual 8086 mode bit */ + +#define PSL_MBZ 0xfffc7fb7 /* must be zero bits */ +#define PSL_MBO 0x00000002 /* must be one bits */ + +#define PSL_USERSET (PSL_IOPL) +#define PSL_USERCLR (PSL_I|PSL_NT) diff --git a/sys/i386/include/pte.h b/sys/i386/include/pte.h new file mode 100644 index 000000000000..4b9841347994 --- /dev/null +++ b/sys/i386/include/pte.h @@ -0,0 +1,136 @@ +/*- + * 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. + * + * @(#)pte.h 5.5 (Berkeley) 5/9/91 + */ + +/* + * 386 page table entry and page table directory + * W.Jolitz, 8/89 + * + * There are two major kinds of pte's: those which have ever existed (and are + * thus either now in core or on the swap device), and those which have + * never existed, but which will be filled on demand at first reference. + * There is a structure describing each. There is also an ancillary + * structure used in page clustering. + */ + +#ifndef LOCORE +struct pde +{ +unsigned int + pd_v:1, /* valid bit */ + pd_prot:2, /* access control */ + pd_mbz1:2, /* reserved, must be zero */ + pd_u:1, /* hardware maintained 'used' bit */ + :1, /* not used */ + pd_mbz2:2, /* reserved, must be zero */ + :3, /* reserved for software */ + pd_pfnum:20; /* physical page frame number of pte's*/ +}; +struct pte +{ +unsigned int + pg_v:1, /* valid bit */ + pg_prot:2, /* access control */ + pg_mbz1:2, /* reserved, must be zero */ + pg_u:1, /* hardware maintained 'used' bit */ + pg_m:1, /* hardware maintained modified bit */ + pg_mbz2:2, /* reserved, must be zero */ + pg_fod:1, /* is fill on demand (=0) */ + :1, /* must write back to swap (unused) */ + pg_nc:1, /* 'uncacheable page' bit */ + pg_pfnum:20; /* physical page frame number */ +}; +struct hpte +{ +unsigned int + pg_high:12, /* special for clustering */ + pg_pfnum:20; +}; +struct fpte +{ +unsigned int + pg_v:1, /* valid bit */ + pg_prot:2, /* access control */ + :5, + pg_fileno:1, /* file mapped from or TEXT or ZERO */ + pg_fod:1, /* is fill on demand (=1) */ + pg_blkno:22; /* file system block number */ +}; +#endif + +#define PD_MASK 0xffc00000 /* page directory address bits */ +#define PD_SHIFT 22 /* page directory address bits */ + +#define PG_V 0x00000001 +#define PG_PROT 0x00000006 /* all protection bits . */ +#define PG_FOD 0x00000200 +#define PG_SWAPM 0x00000400 +#define PG_N 0x00000800 /* Non-cacheable */ +#define PG_M 0x00000040 +#define PG_U 0x00000020 /* not currently used */ +#define PG_FRAME 0xfffff000 + +#define PG_FZERO 0 +#define PG_FTEXT 1 +#define PG_FMAX (PG_FTEXT) + +#define PG_NOACC 0 +#define PG_KR 0x00000000 +#define PG_KW 0x00000002 +#define PG_URKR 0x00000004 +#define PG_URKW 0x00000004 +#define PG_UW 0x00000006 + +/* + * Page Protection Exception bits + */ + +#define PGEX_P 0x01 /* Protection violation vs. not present */ +#define PGEX_W 0x02 /* during a Write cycle */ +#define PGEX_U 0x04 /* access from User mode (UPL) */ + +/* + * Pte related macros + */ +#define dirty(pte) ((pte)->pg_m) + +#ifndef LOCORE +#ifdef KERNEL +/* utilities defined in pmap.c */ +extern struct pte *Sysmap; +#endif +#endif diff --git a/sys/i386/include/reg.h b/sys/i386/include/reg.h new file mode 100644 index 000000000000..bc2f05cf0cfe --- /dev/null +++ b/sys/i386/include/reg.h @@ -0,0 +1,93 @@ +/*- + * 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. + * + * @(#)reg.h 5.5 (Berkeley) 1/18/91 + */ + +/* + * Location of the users' stored + * registers within appropriate frame of 'trap' and 'syscall', relative to + * base of stack frame. + * Normal usage is u.u_ar0[XX] in kernel. + */ + +/* When referenced during a trap/exception, registers are at these offsets */ + +#define tES (0) +#define tDS (1) +#define tEDI (2) +#define tESI (3) +#define tEBP (4) + +#define tEBX (6) +#define tEDX (7) +#define tECX (8) +#define tEAX (9) + +#define tEIP (12) +#define tCS (13) +#define tEFLAGS (14) +#define tESP (15) +#define tSS (16) + +/* During a system call, registers are at these offsets instead of above. */ + +#define sEDI (0) +#define sESI (1) +#define sEBP (2) + +#define sEBX (4) +#define sEDX (5) +#define sECX (6) +#define sEAX (7) +#define sEFLAGS (8) +#define sEIP (9) +#define sCS (10) +#define sESP (11) +#define sSS (12) + +#define PC sEIP +#define SP sESP +#define PS sEFLAGS +#define R0 sEDX +#define R1 sECX +/* + * Registers accessible to ptrace(2) syscall for debugger + */ +#ifdef IPCREG +#define NIPCREG 14 +int ipcreg[NIPCREG] = + { tES,tDS,tEDI,tESI,tEBP,tEBX,tEDX,tECX,tEAX,tEIP,tCS,tEFLAGS,tESP,tSS }; +#endif diff --git a/sys/i386/include/segments.h b/sys/i386/include/segments.h new file mode 100644 index 000000000000..0456e59ac86b --- /dev/null +++ b/sys/i386/include/segments.h @@ -0,0 +1,196 @@ +/*- + * Copyright (c) 1989, 1990 William F. Jolitz + * 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. + * + * @(#)segments.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * 386 Segmentation Data Structures and definitions + * William F. Jolitz (william@ernie.berkeley.edu) 6/20/1989 + */ + +/* + * Selectors + */ + +#define ISPL(s) ((s)&3) /* what is the priority level of a selector */ +#define SEL_KPL 0 /* kernel priority level */ +#define SEL_UPL 3 /* user priority level */ +#define ISLDT(s) ((s)&SEL_LDT) /* is it local or global */ +#define SEL_LDT 4 /* local descriptor table */ +#define IDXSEL(s) (((s)>>3) & 0x1fff) /* index of selector */ +#define LSEL(s,r) (((s)<<3) | SEL_LDT | r) /* a local selector */ +#define GSEL(s,r) (((s)<<3) | r) /* a global selector */ + +/* + * Memory and System segment descriptors + */ +struct segment_descriptor { + unsigned sd_lolimit:16 ; /* segment extent (lsb) */ + unsigned sd_lobase:24 ; /* segment base address (lsb) */ + unsigned sd_type:5 ; /* segment type */ + unsigned sd_dpl:2 ; /* segment descriptor priority level */ + unsigned sd_p:1 ; /* segment descriptor present */ + unsigned sd_hilimit:4 ; /* segment extent (msb) */ + unsigned sd_xx:2 ; /* unused */ + unsigned sd_def32:1 ; /* default 32 vs 16 bit size */ + unsigned sd_gran:1 ; /* limit granularity (byte/page units)*/ + unsigned sd_hibase:8 ; /* segment base address (msb) */ +} ; + +/* + * Gate descriptors (e.g. indirect descriptors) + */ +struct gate_descriptor { + unsigned gd_looffset:16 ; /* gate offset (lsb) */ + unsigned gd_selector:16 ; /* gate segment selector */ + unsigned gd_stkcpy:5 ; /* number of stack wds to cpy */ + unsigned gd_xx:3 ; /* unused */ + unsigned gd_type:5 ; /* segment type */ + unsigned gd_dpl:2 ; /* segment descriptor priority level */ + unsigned gd_p:1 ; /* segment descriptor present */ + unsigned gd_hioffset:16 ; /* gate offset (msb) */ +} ; + +/* + * Generic descriptor + */ +union descriptor { + struct segment_descriptor sd; + struct gate_descriptor gd; +}; + + /* system segments and gate types */ +#define SDT_SYSNULL 0 /* system null */ +#define SDT_SYS286TSS 1 /* system 286 TSS available */ +#define SDT_SYSLDT 2 /* system local descriptor table */ +#define SDT_SYS286BSY 3 /* system 286 TSS busy */ +#define SDT_SYS286CGT 4 /* system 286 call gate */ +#define SDT_SYSTASKGT 5 /* system task gate */ +#define SDT_SYS286IGT 6 /* system 286 interrupt gate */ +#define SDT_SYS286TGT 7 /* system 286 trap gate */ +#define SDT_SYSNULL2 8 /* system null again */ +#define SDT_SYS386TSS 9 /* system 386 TSS available */ +#define SDT_SYSNULL3 10 /* system null again */ +#define SDT_SYS386BSY 11 /* system 386 TSS busy */ +#define SDT_SYS386CGT 12 /* system 386 call gate */ +#define SDT_SYSNULL4 13 /* system null again */ +#define SDT_SYS386IGT 14 /* system 386 interrupt gate */ +#define SDT_SYS386TGT 15 /* system 386 trap gate */ + + /* memory segment types */ +#define SDT_MEMRO 16 /* memory read only */ +#define SDT_MEMROA 17 /* memory read only accessed */ +#define SDT_MEMRW 18 /* memory read write */ +#define SDT_MEMRWA 19 /* memory read write accessed */ +#define SDT_MEMROD 20 /* memory read only expand dwn limit */ +#define SDT_MEMRODA 21 /* memory read only expand dwn limit accessed */ +#define SDT_MEMRWD 22 /* memory read write expand dwn limit */ +#define SDT_MEMRWDA 23 /* memory read write expand dwn limit acessed */ +#define SDT_MEME 24 /* memory execute only */ +#define SDT_MEMEA 25 /* memory execute only accessed */ +#define SDT_MEMER 26 /* memory execute read */ +#define SDT_MEMERA 27 /* memory execute read accessed */ +#define SDT_MEMEC 28 /* memory execute only conforming */ +#define SDT_MEMEAC 29 /* memory execute only accessed conforming */ +#define SDT_MEMERC 30 /* memory execute read conforming */ +#define SDT_MEMERAC 31 /* memory execute read accessed conforming */ + +/* is memory segment descriptor pointer ? */ +#define ISMEMSDP(s) ((s->d_type) >= SDT_MEMRO && (s->d_type) <= SDT_MEMERAC) + +/* is 286 gate descriptor pointer ? */ +#define IS286GDP(s) (((s->d_type) >= SDT_SYS286CGT \ + && (s->d_type) < SDT_SYS286TGT)) + +/* is 386 gate descriptor pointer ? */ +#define IS386GDP(s) (((s->d_type) >= SDT_SYS386CGT \ + && (s->d_type) < SDT_SYS386TGT)) + +/* is gate descriptor pointer ? */ +#define ISGDP(s) (IS286GDP(s) || IS386GDP(s)) + +/* is segment descriptor pointer ? */ +#define ISSDP(s) (ISMEMSDP(s) || !ISGDP(s)) + +/* is system segment descriptor pointer ? */ +#define ISSYSSDP(s) (!ISMEMSDP(s) && !ISGDP(s)) + +/* + * Software definitions are in this convenient format, + * which are translated into inconvenient segment descriptors + * when needed to be used by the 386 hardware + */ + +struct soft_segment_descriptor { + unsigned ssd_base ; /* segment base address */ + unsigned ssd_limit ; /* segment extent */ + unsigned ssd_type:5 ; /* segment type */ + unsigned ssd_dpl:2 ; /* segment descriptor priority level */ + unsigned ssd_p:1 ; /* segment descriptor present */ + unsigned ssd_xx:4 ; /* unused */ + unsigned ssd_xx1:2 ; /* unused */ + unsigned ssd_def32:1 ; /* default 32 vs 16 bit size */ + unsigned ssd_gran:1 ; /* limit granularity (byte/page units)*/ +}; + +extern ssdtosd() ; /* to decode a ssd */ +extern sdtossd() ; /* to encode a sd */ + +/* + * region descriptors, used to load gdt/idt tables before segments yet exist. + */ +struct region_descriptor { + unsigned rd_limit:16; /* segment extent */ + unsigned rd_base:32; /* base address */ +}; + +/* + * Segment Protection Exception code bits + */ + +#define SEGEX_EXT 0x01 /* recursive or externally induced */ +#define SEGEX_IDT 0x02 /* interrupt descriptor table */ +#define SEGEX_TI 0x04 /* local descriptor table */ + /* other bits are affected descriptor index */ +#define SEGEX_IDX(s) ((s)>>3)&0x1fff) + +/* + * Size of IDT table + */ + +#define NIDT 256 +#define NRSVIDT 32 /* reserved entries for cpu exceptions */ diff --git a/sys/i386/include/specialreg.h b/sys/i386/include/specialreg.h new file mode 100644 index 000000000000..d1908c9371b6 --- /dev/null +++ b/sys/i386/include/specialreg.h @@ -0,0 +1,67 @@ +/*- + * 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. + * + * @(#)specialreg.h 7.1 (Berkeley) 5/9/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Bruce Evans New npx-0.5 code + * + */ + +/* + * Bits in 386 special registers: + */ + +#define CR0_PE 0x00000001 /* Protected mode Enable */ +#define CR0_MP 0x00000002 /* "Math" Present (NPX or NPX emulator) */ +#ifdef notused +#define CR0_EM 0x00000004 /* EMulate non-NPX coproc. (trap ESC only) */ +#endif +#define CR0_TS 0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */ +#ifdef notused +#define CR0_ET 0x00000010 /* Extension Type (387 (if set) vs 287) */ +#endif +#define CR0_PG 0x80000000 /* PaGing enable */ + +/* + * Bits in 486 special registers: + */ + +#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */ +#define CR0_WP 0x00010000 /* Write Protect (honor ~PG_W in all modes) */ +#ifdef notyet +#define CR0_AM 0x00040000 /* Alignment Mask (set to enable AC flag) */ +#endif diff --git a/sys/i386/include/stdarg.h b/sys/i386/include/stdarg.h new file mode 100644 index 000000000000..f4992539baef --- /dev/null +++ b/sys/i386/include/stdarg.h @@ -0,0 +1,53 @@ +/*- + * 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. + * + * @(#)stdarg.h 7.2 (Berkeley) 5/4/91 + */ + +typedef char *va_list; + +#ifdef KERNEL +#define va_arg(ap, type) \ + ((type *)(ap += sizeof(type)))[-1] +#else +#define va_arg(ap, type) \ + ((type *)(ap += sizeof(type) < sizeof(int) ? \ + (abort(), 0) : sizeof(type)))[-1] +#endif + +#define va_end(ap) + +#define __va_promote(type) \ + (((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int)) + +#define va_start(ap, last) \ + (ap = ((char *)&(last) + __va_promote(last))) diff --git a/sys/i386/include/trap.h b/sys/i386/include/trap.h new file mode 100644 index 000000000000..601560523d03 --- /dev/null +++ b/sys/i386/include/trap.h @@ -0,0 +1,96 @@ +/*- + * 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. + * + * @(#)trap.h 5.4 (Berkeley) 5/9/91 + */ + +/* + * Trap type values + * also known in trap.c for name strings + */ + +#define T_RESADFLT 0 /* reserved addressing */ +#define T_PRIVINFLT 1 /* privileged instruction */ +#define T_RESOPFLT 2 /* reserved operand */ +#define T_BPTFLT 3 /* breakpoint instruction */ +#define T_SYSCALL 5 /* system call (kcall) */ +#define T_ARITHTRAP 6 /* arithmetic trap */ +#define T_ASTFLT 7 /* system forced exception */ +#define T_SEGFLT 8 /* segmentation (limit) fault */ +#define T_PROTFLT 9 /* protection fault */ +#define T_TRCTRAP 10 /* trace trap */ +#define T_PAGEFLT 12 /* page fault */ +#define T_TABLEFLT 13 /* page table fault */ +#define T_ALIGNFLT 14 /* alignment fault */ +#define T_KSPNOTVAL 15 /* kernel stack pointer not valid */ +#define T_BUSERR 16 /* bus error */ +#define T_KDBTRAP 17 /* kernel debugger trap */ + +#define T_DIVIDE 18 /* integer divide fault */ +#define T_NMI 19 /* non-maskable trap */ +#define T_OFLOW 20 /* overflow trap */ +#define T_BOUND 21 /* bound instruction fault */ +#define T_DNA 22 /* device not available fault */ +#define T_DOUBLEFLT 23 /* double fault */ +#define T_FPOPFLT 24 /* fp coprocessor operand fetch fault */ +#define T_TSSFLT 25 /* invalid tss fault */ +#define T_SEGNPFLT 26 /* segment not present fault */ +#define T_STKFLT 27 /* stack fault */ +#define T_RESERVED 28 /* reserved fault base */ + +/* definitions for <sys/signal.h> */ +#define ILL_RESAD_FAULT T_RESADFLT +#define ILL_PRIVIN_FAULT T_PRIVINFLT +#define ILL_RESOP_FAULT T_RESOPFLT +#define ILL_ALIGN_FAULT T_ALIGNFLT +#define ILL_FPOP_FAULT T_FPOPFLT /* coprocessor operand fault */ + +/* codes for SIGFPE/ARITHTRAP */ +#define FPE_INTOVF_TRAP 0x1 /* integer overflow */ +#define FPE_INTDIV_TRAP 0x2 /* integer divide by zero */ +#define FPE_FLTDIV_TRAP 0x3 /* floating/decimal divide by zero */ +#define FPE_FLTOVF_TRAP 0x4 /* floating overflow */ +#define FPE_FLTUND_TRAP 0x5 /* floating underflow */ +#define FPE_FPU_NP_TRAP 0x6 /* floating point unit not present */ +#define FPE_SUBRNG_TRAP 0x7 /* subrange out of bounds */ + +/* codes for SIGBUS */ +#define BUS_PAGE_FAULT T_PAGEFLT /* page fault protection base */ +#define BUS_SEGNP_FAULT T_SEGNPFLT /* segment not present */ +#define BUS_STK_FAULT T_STKFLT /* stack segment */ +#define BUS_SEGM_FAULT T_RESERVED /* segment protection base */ + +/* Trap's coming from user mode */ +#define T_USER 0x100 diff --git a/sys/i386/include/tss.h b/sys/i386/include/tss.h new file mode 100644 index 000000000000..8ba140d6c7ec --- /dev/null +++ b/sys/i386/include/tss.h @@ -0,0 +1,78 @@ +/*- + * 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. + * + * @(#)tss.h 5.4 (Berkeley) 1/18/91 + */ + +/* + * Intel 386 Context Data Type + */ + +struct i386tss { + int tss_link; /* actually 16 bits: top 16 bits must be zero */ + int tss_esp0; /* kernel stack pointer priviledge level 0 */ +#define tss_ksp tss_esp0 + int tss_ss0; /* actually 16 bits: top 16 bits must be zero */ + int tss_esp1; /* kernel stack pointer priviledge level 1 */ + int tss_ss1; /* actually 16 bits: top 16 bits must be zero */ + int tss_esp2; /* kernel stack pointer priviledge level 2 */ + int tss_ss2; /* actually 16 bits: top 16 bits must be zero */ + /* struct ptd *tss_cr3; /* page table directory */ + int tss_cr3; /* page table directory */ +#define tss_ptd tss_cr3 + int tss_eip; /* program counter */ +#define tss_pc tss_eip + int tss_eflags; /* program status longword */ +#define tss_psl tss_eflags + int tss_eax; + int tss_ecx; + int tss_edx; + int tss_ebx; + int tss_esp; /* user stack pointer */ +#define tss_usp tss_esp + int tss_ebp; /* user frame pointer */ +#define tss_fp tss_ebp + int tss_esi; + int tss_edi; + int tss_es; /* actually 16 bits: top 16 bits must be zero */ + int tss_cs; /* actually 16 bits: top 16 bits must be zero */ + int tss_ss; /* actually 16 bits: top 16 bits must be zero */ + int tss_ds; /* actually 16 bits: top 16 bits must be zero */ + int tss_fs; /* actually 16 bits: top 16 bits must be zero */ + int tss_gs; /* actually 16 bits: top 16 bits must be zero */ + int tss_ldt; /* actually 16 bits: top 16 bits must be zero */ + int tss_ioopt; /* options & io offset bitmap: currently zero */ + /* XXX unimplemented .. i/o permission bitmap */ +}; diff --git a/sys/i386/include/types.h b/sys/i386/include/types.h new file mode 100644 index 000000000000..9eeaef3cd73a --- /dev/null +++ b/sys/i386/include/types.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 1990 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. + * + * @(#)types.h 7.5 (Berkeley) 3/9/91 + */ + +#ifndef _MACHTYPES_H_ +#define _MACHTYPES_H_ + +typedef struct _physadr { + int r[1]; +} *physadr; + +typedef struct label_t { + int val[6]; +} label_t; + +typedef u_long vm_offset_t; +typedef u_long vm_size_t; + +#endif /* _MACHTYPES_H_ */ diff --git a/sys/i386/include/vmparam.h b/sys/i386/include/vmparam.h new file mode 100644 index 000000000000..39403d6aba6e --- /dev/null +++ b/sys/i386/include/vmparam.h @@ -0,0 +1,256 @@ +/*- + * 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. + * + * @(#)vmparam.h 5.9 (Berkeley) 5/12/91 + */ + + +/* + * Machine dependent constants for 386. + */ + +/* + * Virtual address space arrangement. On 386, both user and kernel + * share the address space, not unlike the vax. + * USRTEXT is the start of the user text/data space, while USRSTACK + * is the top (end) of the user stack. Immediately above the user stack + * resides the user structure, which is UPAGES long and contains the + * kernel stack. + * + * Immediately after the user structure is the page table map, and then + * kernal address space. + */ +#define USRTEXT 0 +#define USRSTACK 0xFDBFE000 +#define BTOPUSRSTACK (0xFDC00-(UPAGES)) /* btop(USRSTACK) */ +#define LOWPAGES 0 +#define HIGHPAGES UPAGES + +/* + * Virtual memory related constants, all in bytes + */ +#define MAXTSIZ (6*1024*1024) /* max text size */ +#ifndef DFLDSIZ +#define DFLDSIZ (6*1024*1024) /* initial data size limit */ +#endif +#ifndef MAXDSIZ +#define MAXDSIZ (32*1024*1024) /* max data size */ +#endif +#ifndef DFLSSIZ +#define DFLSSIZ (512*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. + */ +#define DMMIN 32 /* smallest swap allocation */ +#define DMMAX 4096 /* largest potential swap allocation */ +#define DMTEXT 1024 /* swap allocation for text */ + +/* + * Sizes of the system and user portions of the system page table. + */ +#define SYSPTSIZE (2*NPTEPG) +#define USRPTSIZE (2*NPTEPG) + +/* + * Size of User Raw I/O map + */ +#define USRIOSIZE 300 + +/* + * 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. + * { wfj 6/16/89: Retail AT memory expansion $800/megabyte, loan of $17 + * on disk costing $7/mb or $0.18 (in memory still 100:1 in cost!) } + */ +#define SAFERSS 8 /* 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 KLMAX*CLSIZE must be <= DMMIN in dmap.h. + */ + +#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) + +/* + * 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 + * minfree is 64k bytes, but at most 1/2 of desfree + */ +#define LOTSFREE (512 * 1024) +#define LOTSFREEFRACT 4 +#define DESFREE (200 * 1024) +#define DESFREEFRACT 8 +#define MINFREE (64 * 1024) +#define MINFREEFRACT 2 + +/* + * 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)<<PGSHIFT) | (prot)) ; } + +/* + * Mach derived constants + */ + +/* user/kernel map constants */ +#define VM_MIN_ADDRESS ((vm_offset_t)0) +#define VM_MAXUSER_ADDRESS ((vm_offset_t)0xFDBFE000) +#define UPT_MIN_ADDRESS ((vm_offset_t)0xFDC00000) +#define UPT_MAX_ADDRESS ((vm_offset_t)0xFDFF7000) +#define VM_MAX_ADDRESS UPT_MAX_ADDRESS +#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)0xFDFF7000) +#define UPDT VM_MIN_KERNEL_ADDRESS +#define KPT_MIN_ADDRESS ((vm_offset_t)0xFDFF8000) +#define KPT_MAX_ADDRESS ((vm_offset_t)0xFDFFF000) +#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t)0xFF7FF000) + +/* 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) + +/* # of kernel PT pages (initial only, can grow dynamically) */ +#define VM_KERNEL_PT_PAGES ((vm_size_t)2) /* XXX: SYSPTSIZE */ + +/* pcb base */ +#define pcbb(p) ((u_int)(p)->p_addr) + +/* + * Flush MMU TLB + */ + +#ifndef I386_CR3PAT +#define I386_CR3PAT 0x0 +#endif + +#ifdef notyet +#define _cr3() ({u_long rtn; \ + asm (" movl %%cr3,%%eax; movl %%eax,%0 " \ + : "=g" (rtn) \ + : \ + : "ax"); \ + rtn; \ +}) + +#define load_cr3(s) ({ u_long val; \ + val = (s) | I386_CR3PAT; \ + asm ("movl %0,%%eax; movl %%eax,%%cr3" \ + : \ + : "g" (val) \ + : "ax"); \ +}) + +#define tlbflush() ({ u_long val; \ + val = u.u_pcb.pcb_ptd | I386_CR3PAT; \ + asm ("movl %0,%%eax; movl %%eax,%%cr3" \ + : \ + : "g" (val) \ + : "ax"); \ +}) +#endif diff --git a/sys/i386/isa/aha1542.c b/sys/i386/isa/aha1542.c new file mode 100644 index 000000000000..85271fcf978f --- /dev/null +++ b/sys/i386/isa/aha1542.c @@ -0,0 +1,1644 @@ +/* + * (Mostly) Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + */ + +/* + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + */ + +/* + * HISTORY + * $Log: aha1542.c,v $ + * Revision 1.6 1992/08/24 21:01:58 jason + * many changes and bugfixes for osf1 + * + * Revision 1.5 1992/07/31 01:22:03 julian + * support improved scsi.h layout + * + * Revision 1.4 1992/07/25 03:11:26 julian + * check each request fro sane flags. + * + * Revision 1.3 1992/07/24 00:52:45 julian + * improved timeout handling. + * added support for two arguments to the sd_done (or equiv) call so that + * they can pre-queue several arguments. + * slightly clean up error handling + * + * Revision 1.2 1992/07/17 22:03:54 julian + * upgraded the timeout code. + * added support for UIO-based i/o (as used for pmem operations) + * + * Revision 1.1 1992/05/27 00:51:12 balsup + * machkern/cor merge + */ + +/* + * a FEW lines in this driver come from a MACH adaptec-disk driver + * so the copyright below is included: + * + * Copyright 1990 by Open Software Foundation, + * Grenoble, FRANCE + * + * 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 OSF or Open Software + * Foundation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. + * + * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL OSF 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/types.h> +#include <aha.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/user.h> + +#ifdef MACH /* EITHER CMU OR OSF */ +#include <i386/ipl.h> +#include <i386at/scsi.h> +#include <i386at/scsiconf.h> + +#ifdef OSF /* OSF ONLY */ +#include <sys/table.h> +#include <i386/handler.h> +#include <i386/dispatcher.h> +#include <i386/AT386/atbus.h> + +#else OSF /* CMU ONLY */ +#include <i386at/atbus.h> +#include <i386/pio.h> +#endif OSF +#endif MACH /* end of MACH specific */ + +#ifdef __386BSD__ /* 386BSD specific */ +#define isa_dev isa_device +#define dev_unit id_unit +#define dev_addr id_iobase + +#include <i386/isa/isa_device.h> +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> +#endif __386BSD__ + + +#ifdef __386BSD__ +#include "ddb.h" +#if NDDB > 0 +int Debugger(); +#else NDDB +#define Debugger() panic("should call debugger here (adaptec.c)") +#endif NDDB +#endif __386BSD__ +extern int delaycount; /* from clock setup code */ + +/************************** board definitions *******************************/ +/* + * I/O Port Interface + */ + +#define AHA_BASE aha_base[unit] +#define AHA_CTRL_STAT_PORT (AHA_BASE + 0x0) /* control & status */ +#define AHA_CMD_DATA_PORT (AHA_BASE + 0x1) /* cmds and datas */ +#define AHA_INTR_PORT (AHA_BASE + 0x2) /* Intr. stat */ + +/* + * AHA_CTRL_STAT bits (write) + */ + +#define AHA_HRST 0x80 /* Hardware reset */ +#define AHA_SRST 0x40 /* Software reset */ +#define AHA_IRST 0x20 /* Interrupt reset */ +#define AHA_SCRST 0x10 /* SCSI bus reset */ + +/* + * AHA_CTRL_STAT bits (read) + */ + +#define AHA_STST 0x80 /* Self test in Progress */ +#define AHA_DIAGF 0x40 /* Diagnostic Failure */ +#define AHA_INIT 0x20 /* Mbx Init required */ +#define AHA_IDLE 0x10 /* Host Adapter Idle */ +#define AHA_CDF 0x08 /* cmd/data out port full */ +#define AHA_DF 0x04 /* Data in port full */ +#define AHA_INVDCMD 0x01 /* Invalid command */ + +/* + * AHA_CMD_DATA bits (write) + */ + +#define AHA_NOP 0x00 /* No operation */ +#define AHA_MBX_INIT 0x01 /* Mbx initialization */ +#define AHA_START_SCSI 0x02 /* start scsi command */ +#define AHA_START_BIOS 0x03 /* start bios command */ +#define AHA_INQUIRE 0x04 /* Adapter Inquiry */ +#define AHA_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */ +#define AHA_SEL_TIMEOUT_SET 0x06 /* set selection time-out */ +#define AHA_BUS_ON_TIME_SET 0x07 /* set bus-on time */ +#define AHA_BUS_OFF_TIME_SET 0x08 /* set bus-off time */ +#define AHA_SPEED_SET 0x09 /* set transfer speed */ +#define AHA_DEV_GET 0x0a /* return installed devices */ +#define AHA_CONF_GET 0x0b /* return configuration data */ +#define AHA_TARGET_EN 0x0c /* enable target mode */ +#define AHA_SETUP_GET 0x0d /* return setup data */ +#define AHA_WRITE_CH2 0x1a /* write channel 2 buffer */ +#define AHA_READ_CH2 0x1b /* read channel 2 buffer */ +#define AHA_WRITE_FIFO 0x1c /* write fifo buffer */ +#define AHA_READ_FIFO 0x1d /* read fifo buffer */ +#define AHA_ECHO 0x1e /* Echo command data */ + +struct aha_cmd_buf { + u_char byte[16]; +}; + +/* + * AHA_INTR_PORT bits (read) + */ + +#define AHA_ANY_INTR 0x80 /* Any interrupt */ +#define AHA_SCRD 0x08 /* SCSI reset detected */ +#define AHA_HACC 0x04 /* Command complete */ +#define AHA_MBOA 0x02 /* MBX out empty */ +#define AHA_MBIF 0x01 /* MBX in full */ + +/* + * Mail box defs + */ + +#define AHA_MBX_SIZE 16 /* mail box size */ + +struct aha_mbx { + struct aha_mbx_out { + unsigned char cmd; + unsigned char ccb_addr[3]; + } mbo [AHA_MBX_SIZE]; + struct aha_mbx_in{ + unsigned char stat; + unsigned char ccb_addr[3]; + } mbi[AHA_MBX_SIZE]; +}; + +/* + * mbo.cmd values + */ + +#define AHA_MBO_FREE 0x0 /* MBO entry is free */ +#define AHA_MBO_START 0x1 /* MBO activate entry */ +#define AHA_MBO_ABORT 0x2 /* MBO abort entry */ + +#define AHA_MBI_FREE 0x0 /* MBI entry is free */ +#define AHA_MBI_OK 0x1 /* completed without error */ +#define AHA_MBI_ABORT 0x2 /* aborted ccb */ +#define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ +#define AHA_MBI_ERROR 0x4 /* Completed with error */ + +extern struct aha_mbx aha_mbx[]; + +/* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */ +#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */ + /* allow 64 K i/o (min) */ + +struct aha_ccb { + unsigned char opcode; + unsigned char lun:3; + unsigned char data_in:1; /* must be 0 */ + unsigned char data_out:1; /* must be 0 */ + unsigned char target:3; + unsigned char scsi_cmd_length; + unsigned char req_sense_length; + unsigned char data_length[3]; + unsigned char data_addr[3]; + unsigned char link_addr[3]; + unsigned char link_id; + unsigned char host_stat; + unsigned char target_stat; + unsigned char reserved[2]; + struct scsi_generic scsi_cmd; + struct scsi_sense_data scsi_sense; + struct aha_scat_gath { + unsigned char seg_len[3]; + unsigned char seg_addr[3]; + } scat_gath[AHA_NSEG]; + struct aha_ccb *next; + struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ + struct aha_mbx_out *mbx; /* pointer to mail box */ + long int delta; /* difference from previous*/ + struct aha_ccb *later,*sooner; + int flags; +#define CCB_FREE 0 +#define CCB_ACTIVE 1 +#define CCB_ABORTED 2 + +}; + +struct aha_ccb *aha_soonest = (struct aha_ccb *)0; +struct aha_ccb *aha_latest = (struct aha_ccb *)0; +long int aha_furtherest = 0; /* longest time in the timeout queue */ + +/* + * opcode fields + */ + +#define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ +#define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */ +#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather*/ +#define AHA_RESET_CCB 0x81 /* SCSI Bus reset */ + + +/* + * aha_ccb.host_stat values + */ + +#define AHA_OK 0x00 /* cmd ok */ +#define AHA_LINK_OK 0x0a /* Link cmd ok */ +#define AHA_LINK_IT 0x0b /* Link cmd ok + int */ +#define AHA_SEL_TIMEOUT 0x11 /* Selection time out */ +#define AHA_OVER_UNDER 0x12 /* Data over/under run */ +#define AHA_BUS_FREE 0x13 /* Bus dropped at unexpected time */ +#define AHA_INV_BUS 0x14 /* Invalid bus phase/sequence */ +#define AHA_BAD_MBO 0x15 /* Incorrect MBO cmd */ +#define AHA_BAD_CCB 0x16 /* Incorrect ccb opcode */ +#define AHA_BAD_LINK 0x17 /* Not same values of LUN for links */ +#define AHA_INV_TARGET 0x18 /* Invalid target direction */ +#define AHA_CCB_DUP 0x19 /* Duplicate CCB received */ +#define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */ +#define AHA_ABORTED 42 + + + + +struct aha_setup +{ + u_char sync_neg:1; + u_char parity:1; + u_char :6; + u_char speed; + u_char bus_on; + u_char bus_off; + u_char num_mbx; + u_char mbx[3]; + struct + { + u_char offset:4; + u_char period:3; + u_char valid:1; + }sync[8]; + u_char disc_sts; +}; + +struct aha_config +{ + u_char chan; + u_char intr; + u_char scsi_dev:3; + u_char :5; +}; + +#define INT9 0x01 +#define INT10 0x02 +#define INT11 0x04 +#define INT12 0x08 +#define INT14 0x20 +#define INT15 0x40 + +#define CHAN0 0x01 +#define CHAN5 0x20 +#define CHAN6 0x40 +#define CHAN7 0x80 + + +/*********************************** end of board definitions***************/ + + +#ifdef MACH +#define PHYSTOKV(x) phystokv(x) +#define KVTOPHYS(x) kvtophys(x) +#else MACH +#ifdef __386BSD__ +#define PHYSTOKV(x) (x | 0xFE000000) +#define KVTOPHYS(x) vtophys(x) +#else __386BSD__ +#endif __386BSD__ +#endif MACH +#define AHA_DMA_PAGES AHA_NSEG + +#define PAGESIZ 4096 +#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); } + + +u_char aha_scratch_buf[256]; +#ifdef MACH +caddr_t aha_base[NAHA]; /* base port for each board */ +#else +short aha_base[NAHA]; /* base port for each board */ +#endif +struct aha_mbx aha_mbx[NAHA]; +struct aha_ccb *aha_ccb_free[NAHA]; +struct aha_ccb aha_ccb[NAHA][AHA_MBX_SIZE]; +struct scsi_xfer aha_scsi_xfer[NAHA]; +struct isa_dev *ahainfo[NAHA]; +struct aha_ccb *aha_get_ccb(); +int aha_int[NAHA]; +int aha_dma[NAHA]; +int aha_scsi_dev[NAHA]; +int aha_initialized[NAHA]; +#ifdef OSF +int aha_attached[NAHA]; +#endif OSF +int aha_debug = 0; + +int ahaprobe(), ahaattach(), ahaintr(); +#ifdef MACH +struct isa_driver ahadriver = { ahaprobe, 0, ahaattach, "aha", 0, 0, 0}; +int (*ahaintrs[])() = {ahaintr, 0}; +#endif +#ifdef __386BSD__ +struct isa_driver ahadriver = { ahaprobe, ahaattach, "aha",}; +#endif __386BSD__ +static int ahaunit = 0; + + +#define aha_abortmbx(mbx) \ + (mbx)->cmd = AHA_MBO_ABORT; \ + outb(AHA_CMD_DATA_PORT, AHA_START_SCSI); +#define aha_startmbx(mbx) \ + (mbx)->cmd = AHA_MBO_START; \ + outb(AHA_CMD_DATA_PORT, AHA_START_SCSI); + + + +int aha_scsi_cmd(); +int aha_timeout(); +void ahaminphys(); +long int aha_adapter_info(); + +struct scsi_switch aha_switch = +{ + aha_scsi_cmd, + ahaminphys, + 0, + 0, + aha_adapter_info, + 0,0,0 +}; +#define AHA_CMD_TIMEOUT_FUDGE 200 /* multiplied to get Secs */ +#define AHA_RESET_TIMEOUT 1000000 /* time to wait for reset */ +#define AHA_SCSI_TIMEOUT_FUDGE 20 /* divided by for mSecs */ + + +/***********************************************************************\ +* aha_cmd(unit,icnt, ocnt,wait, retval, opcode, args) * +* Activate Adapter command * +* icnt: number of args (outbound bytes written after opcode) * +* ocnt: number of expected returned bytes * +* wait: number of seconds to wait for response * +* retval: buffer where to place returned bytes * +* opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ... * +* args: parameters * +* * +* Performs an adapter command through the ports. Not to be confused * +* with a scsi command, which is read in via the dma * +* One of the adapter commands tells it to read in a scsi command * +\***********************************************************************/ + + +aha_cmd(unit,icnt, ocnt, wait,retval, opcode, args) + +u_char *retval; +unsigned opcode; +u_char args; +{ + unsigned *ic = &opcode; + u_char oc; + register i; + int sts; + + /*******************************************************\ + * multiply the wait argument by a big constant * + * zero defaults to 1 * + \*******************************************************/ + if(!wait) + wait = AHA_CMD_TIMEOUT_FUDGE * delaycount; + else + wait *= AHA_CMD_TIMEOUT_FUDGE * delaycount; + /*******************************************************\ + * Wait for the adapter to go idle, unless it's one of * + * the commands which don't need this * + \*******************************************************/ + if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI) + { + i = AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec?*/ + while (--i) + { + sts = inb(AHA_CTRL_STAT_PORT); + if (sts & AHA_IDLE) + { + break; + } + } + if (!i) + { + printf("aha_cmd: aha1542 host not idle(0x%x)\n",sts); + return(ENXIO); + } + } + /*******************************************************\ + * Now that it is idle, if we expect output, preflush the* + * queue feeding to us. * + \*******************************************************/ + if (ocnt) + { + while((inb(AHA_CTRL_STAT_PORT)) & AHA_DF) + inb(AHA_CMD_DATA_PORT); + } + + /*******************************************************\ + * Output the command and the number of arguments given * + * for each byte, first check the port is empty. * + \*******************************************************/ + icnt++; /* include the command */ + while (icnt--) + { + sts = inb(AHA_CTRL_STAT_PORT); + for (i=0; i< wait; i++) + { + sts = inb(AHA_CTRL_STAT_PORT); + if (!(sts & AHA_CDF)) + break; + } + if (i >= wait) + { + printf("aha_cmd: aha1542 cmd/data port full\n"); + outb(AHA_CTRL_STAT_PORT, AHA_SRST); + return(ENXIO); + } + outb(AHA_CMD_DATA_PORT, (u_char)(*ic++)); + } + /*******************************************************\ + * If we expect input, loop that many times, each time, * + * looking for the data register to have valid data * + \*******************************************************/ + while (ocnt--) + { + sts = inb(AHA_CTRL_STAT_PORT); + for (i=0; i< wait; i++) + { + sts = inb(AHA_CTRL_STAT_PORT); + if (sts & AHA_DF) + break; + } + if (i >= wait) + { + printf("aha_cmd: aha1542 cmd/data port empty %d\n",ocnt); + return(ENXIO); + } + oc = inb(AHA_CMD_DATA_PORT); + if (retval) + *retval++ = oc; + } + /*******************************************************\ + * Wait for the board to report a finised instruction * + \*******************************************************/ + i=AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */ + while (--i) + { + sts = inb(AHA_INTR_PORT); + if (sts & AHA_HACC) + { + break; + } + } + if (!i) + { + printf("aha_cmd: aha1542 host not finished(0x%x)\n",sts); + return(ENXIO); + } + outb(AHA_CTRL_STAT_PORT, AHA_IRST); + return(0); +} + +/*******************************************************\ +* Check if the device can be found at the port given * +* and if so, set it up ready for further work * +* as an argument, takes the isa_dev structure from * +* autoconf.c * +\*******************************************************/ +ahaprobe(dev) +struct isa_dev *dev; +{ + int unit = ahaunit; +#if defined(OSF) + static ihandler_t aha_handler[NAHA]; + static ihandler_id_t *aha_handler_id[NAHA]; + register ihandler_t *chp = &aha_handler[unit];; +#endif /* defined(OSF) */ + + /***********************************************\ + /***********************************************\ + * find unit and check we have that many defined * + \***********************************************/ + dev->dev_unit = unit; + aha_base[unit] = dev->dev_addr; + if(unit >= NAHA) + { + printf("aha: unit number (%d) too high\n",unit); + return(0); + } + /***********************************************\ + * Try initialise a unit at this location * + * sets up dma and bus speed, loads aha_int[unit]* + \***********************************************/ + if (aha_init(unit) != 0) + { + return(0); + } + + /***********************************************\ + * If it's there, put in it's interrupt vectors * + \***********************************************/ +#if !defined(OSF) +#if defined MACH + iunit[aha_int[unit]] =unit; + ivect[aha_int[unit]] = ahaintr; + intpri[aha_int[unit]] = dev->dev_spl; + form_pic_mask(); + /*take_dev_irq(dev);*/ +#else +#ifdef __386BSD__ + dev->id_irq = (1 << aha_int[unit]); + dev->id_drq = aha_dma[unit]; +#endif __386BSD__ +#endif +#else /* !defined(OSF) */ + + chp->ih_level = dev->dev_pic; + chp->ih_handler = dev->dev_intr[0]; + chp->ih_resolver = i386_resolver; + chp->ih_rdev = dev; + chp->ih_stats.intr_type = INTR_DEVICE; + chp->ih_stats.intr_cnt = 0; + chp->ih_hparam[0].intparam = unit; + if ((aha_handler_id[unit] = handler_add(chp)) != NULL) + handler_enable(aha_handler_id[unit]); + else + panic("Unable to add aha interrupt handler"); +#endif /* !defined(OSF) */ +#ifdef __386BSD__ + printf("\n **"); +#else __386BSD__ + printf("port=%x spl=%d\n", + dev->dev_addr, dev->dev_spl); +#endif __386BSD__ + ahaunit ++; + return(1); +} + +/***********************************************\ +* Attach all the sub-devices we can find * +\***********************************************/ +ahaattach(dev) +struct isa_dev *dev; +{ + int unit = dev->dev_unit; + +#ifdef __386BSD__ + printf(" probing for scsi devices**\n"); +#endif __386BSD__ + /***********************************************\ + * ask the adapter what subunits are present * + \***********************************************/ + scsi_attachdevs( unit, aha_scsi_dev[unit], &aha_switch); +#if defined(OSF) + aha_attached[unit]=1; +#endif /* defined(OSF) */ + if(!unit) /* only one for all boards */ + { + aha_timeout(0); + } +#ifdef __386BSD__ + printf("aha%d",unit); +#endif __386BSD__ + return; + +} + + +/***********************************************\ +* Return some information to the caller about * +* the adapter and it's capabilities * +\***********************************************/ +long int aha_adapter_info(unit) +int unit; +{ + return(2); /* 2 outstanding requests at a time per device */ +} + +/***********************************************\ +* Catch an interrupt from the adaptor * +\***********************************************/ +ahaintr(unit) +{ + struct aha_ccb *ccb; + unsigned char stat; + register i; + + if(scsi_debug & PRINTROUTINES) + printf("ahaintr "); + /***********************************************\ + * First acknowlege the interrupt, Then if it's * + * not telling about a completed operation * + * just return. * + \***********************************************/ + stat = inb(AHA_INTR_PORT); + outb(AHA_CTRL_STAT_PORT, AHA_IRST); + if(scsi_debug & TRACEINTERRUPTS) + printf("int "); + if (! (stat & AHA_MBIF)) + return(1); + if(scsi_debug & TRACEINTERRUPTS) + printf("b "); +#if defined(OSF) + if (!aha_attached[unit]) + { + return(1); + } +#endif /* defined(OSF) */ + /***********************************************\ + * If it IS then process the competed operation * + \***********************************************/ + for (i = 0; i < AHA_MBX_SIZE; i++) + { + if (aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE) + { + ccb = (struct aha_ccb *)PHYSTOKV( + (_3btol(aha_mbx[unit].mbi[i].ccb_addr))); + + if((stat = aha_mbx[unit].mbi[i].stat) != AHA_MBI_OK) + { + switch(stat) + { + case AHA_MBI_ABORT: + if(aha_debug) + printf("abort"); + ccb->host_stat = AHA_ABORTED; + break; + + case AHA_MBI_UNKNOWN: + ccb = (struct aha_ccb *)0; + if(aha_debug) + printf("unknown ccb for abort "); + /* may have missed it */ + /* no such ccb known for abort */ + + case AHA_MBI_ERROR: + break; + + default: + panic("Impossible mbxi status"); + + } + if( aha_debug && ccb ) + { + u_char *cp; + cp = (u_char *)(&(ccb->scsi_cmd)); + printf("op=%x %x %x %x %x %x\n", + cp[0], cp[1], cp[2], + cp[3], cp[4], cp[5]); + printf("stat %x for mbi[%d]\n" + , aha_mbx[unit].mbi[i].stat, i); + printf("addr = 0x%x\n", ccb); + } + } + if(ccb) + { + aha_remove_timeout(ccb); + aha_done(unit,ccb); + } + aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE; + } + } + return(1); +} + +/***********************************************\ +* A ccb (and hence a mbx-out is put onto the * +* free list. * +\***********************************************/ +aha_free_ccb(unit,ccb, flags) +struct aha_ccb *ccb; +{ + unsigned int opri; + + if(scsi_debug & PRINTROUTINES) + printf("ccb%d(0x%x)> ",unit,flags); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + + ccb->next = aha_ccb_free[unit]; + aha_ccb_free[unit] = ccb; + ccb->flags = CCB_FREE; + if(ccb->sooner || ccb->later) + { + printf("yikes, still in timeout queue\n"); + aha_remove_timeout(ccb); + } + /***********************************************\ + * If there were none, wake abybody waiting for * + * one to come free, starting with queued entries* + \***********************************************/ + if (!ccb->next) { + wakeup(&aha_ccb_free[unit]); + } + if (!(flags & SCSI_NOMASK)) + splx(opri); +} + +/***********************************************\ +* Get a free ccb (and hence mbox-out entry) * +\***********************************************/ +struct aha_ccb * +aha_get_ccb(unit,flags) +{ + unsigned opri; + struct aha_ccb *rc; + + if(scsi_debug & PRINTROUTINES) + printf("<ccb%d(0x%x) ",unit,flags); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + /***********************************************\ + * If we can and have to, sleep waiting for one * + * to come free * + \***********************************************/ + while ((!(rc = aha_ccb_free[unit])) && (!(flags & SCSI_NOSLEEP))) + { + sleep(&aha_ccb_free[unit], PRIBIO); + } + if (rc) + { + aha_ccb_free[unit] = aha_ccb_free[unit]->next; + rc->flags = CCB_ACTIVE; + } + if (!(flags & SCSI_NOMASK)) + splx(opri); + return(rc); +} + + +/***********************************************\ +* We have a ccb which has been processed by the * +* adaptor, now we look to see how the operation * +* went. Wake up the owner if waiting * +\***********************************************/ +aha_done(unit,ccb) +struct aha_ccb *ccb; +{ + struct scsi_sense_data *s1,*s2; + struct scsi_xfer *xs = ccb->xfer; + + if(scsi_debug & PRINTROUTINES ) + printf("aha_done "); + /***********************************************\ + * Otherwise, put the results of the operation * + * into the xfer and call whoever started it * + \***********************************************/ + if(!(xs->flags & INUSE)) + { + printf("exiting but not in use! "); + Debugger(); + } + if ( ( ccb->host_stat != AHA_OK + || ccb->target_stat != SCSI_OK) + && (!(xs->flags & SCSI_ERR_OK))) + { + s1 = (struct scsi_sense_data *)(((char *)(&ccb->scsi_cmd)) + + ccb->scsi_cmd_length); + s2 = &(xs->sense); + + if(ccb->host_stat) + { + switch(ccb->host_stat) + { + case AHA_ABORTED: + case AHA_SEL_TIMEOUT: /* No response */ + xs->error = XS_TIMEOUT; + break; + default: /* Other scsi protocol messes */ + xs->error = XS_DRIVER_STUFFUP; + if (aha_debug > 1) + { + printf("host_stat%x\n", + ccb->host_stat); + } + } + + } + else + { + switch(ccb->target_stat) + { + case 0x02: + /* structure copy!!!!!*/ + *s2=*s1; + xs->error = XS_SENSE; + break; + case 0x08: + xs->error = XS_BUSY; + break; + default: + if (aha_debug > 1) + { + printf("target_stat%x\n", + ccb->target_stat); + } + xs->error = XS_DRIVER_STUFFUP; + } + } + } + else /* All went correctly OR errors expected */ + { + xs->resid = 0; + } + xs->flags |= ITSDONE; + aha_free_ccb(unit,ccb, xs->flags); + if(xs->when_done) + (*(xs->when_done))(xs->done_arg,xs->done_arg2); +} + + +/***********************************************\ +* Start the board, ready for normal operation * +\***********************************************/ +aha_init(unit) +int unit; +{ + unsigned char ad[3]; + volatile int i,sts; + struct aha_config conf; + + /***********************************************\ + * reset board, If it doesn't respond, assume * + * that it's not there.. good for the probe * + \***********************************************/ + + outb(AHA_CTRL_STAT_PORT, AHA_HRST|AHA_SRST); + + for (i=0; i < AHA_RESET_TIMEOUT; i++) + { + sts = inb(AHA_CTRL_STAT_PORT) ; + if ( sts == (AHA_IDLE | AHA_INIT)) + break; + } + if (i >= AHA_RESET_TIMEOUT) + { + if (aha_debug) + printf("aha_init: No answer from adaptec board\n"); + return(ENXIO); + } + + /***********************************************\ + * Assume we have a board at this stage * + * setup dma channel from jumpers and save int * + * level * + \***********************************************/ +#ifdef __386BSD__ + printf("aha%d reading board settings, ",unit); +#define PRNT(x) +#else __386BSD__ + printf("aha%d:",unit); +#define PRNT(x) printf(x) +#endif __386BSD__ + aha_cmd(unit,0, sizeof(conf), 0 ,&conf, AHA_CONF_GET); + switch(conf.chan) + { + case CHAN0: + outb(0x0b, 0x0c); + outb(0x0a, 0x00); + aha_dma[unit] = 0; + PRNT("dma=0 "); + break; + case CHAN5: + outb(0xd6, 0xc1); + outb(0xd4, 0x01); + aha_dma[unit] = 5; + PRNT("dma=5 "); + break; + case CHAN6: + outb(0xd6, 0xc2); + outb(0xd4, 0x02); + aha_dma[unit] = 6; + PRNT("dma=6 "); + break; + case CHAN7: + outb(0xd6, 0xc3); + outb(0xd4, 0x03); + aha_dma[unit] = 7; + PRNT("dma=7 "); + break; + default: + printf("illegal dma jumper setting\n"); + return(EIO); + } + switch(conf.intr) + { + case INT9: + aha_int[unit] = 9; + PRNT("int=9 "); + break; + case INT10: + aha_int[unit] = 10; + PRNT("int=10 "); + break; + case INT11: + aha_int[unit] = 11; + PRNT("int=11 "); + break; + case INT12: + aha_int[unit] = 12; + PRNT("int=12 "); + break; + case INT14: + aha_int[unit] = 14; + PRNT("int=14 "); + break; + case INT15: + aha_int[unit] = 15; + PRNT("int=15 "); + break; + default: + printf("illegal int jumper setting\n"); + return(EIO); + } + /* who are we on the scsi bus */ + aha_scsi_dev[unit] = conf.scsi_dev; + + + /***********************************************\ + * Initialize memory transfer speed * + \***********************************************/ + if(!(aha_set_bus_speed(unit))) + { + return(EIO); + } + + + /***********************************************\ + * Initialize mail box * + \***********************************************/ + + lto3b(KVTOPHYS(&aha_mbx[unit]), ad); + + aha_cmd(unit,4, 0, 0, 0, AHA_MBX_INIT, + AHA_MBX_SIZE, + ad[0], + ad[1], + ad[2]); + + + /***********************************************\ + * link the ccb's with the mbox-out entries and * + * into a free-list * + \***********************************************/ + for (i=0; i < AHA_MBX_SIZE; i++) { + aha_ccb[unit][i].next = aha_ccb_free[unit]; + aha_ccb_free[unit] = &aha_ccb[unit][i]; + aha_ccb_free[unit]->flags = CCB_FREE; + aha_ccb_free[unit]->mbx = &aha_mbx[unit].mbo[i]; + lto3b(KVTOPHYS(aha_ccb_free[unit]), aha_mbx[unit].mbo[i].ccb_addr); + } + + /***********************************************\ + * Note that we are going and return (to probe) * + \***********************************************/ + aha_initialized[unit]++; + return(0); +} + + + + + +void ahaminphys(bp) +struct buf *bp; +{ +#ifdef MACH +#if !defined(OSF) + bp->b_flags |= B_NPAGES; /* can support scat/gather */ +#endif /* !defined(OSF) */ +#endif MACH +/* aha seems to explode with 17 segs (64k may require 17 segs) */ +/* on old boards so use a max of 16 segs if you have problems here*/ + if(bp->b_bcount > ((AHA_NSEG - 1) * PAGESIZ)) + { + bp->b_bcount = ((AHA_NSEG - 1) * PAGESIZ); + } +} + +/***********************************************\ +* start a scsi operation given the command and * +* the data address. Also needs the unit, target * +* and lu * +\***********************************************/ +int aha_scsi_cmd(xs) +struct scsi_xfer *xs; +{ + struct scsi_sense_data *s1,*s2; + struct aha_ccb *ccb; + struct aha_scat_gath *sg; + int seg; /* scatter gather seg being worked on */ + int i = 0; + int rc = 0; + int thiskv; + int thisphys,nextphys; + int unit =xs->adapter; + int bytes_this_seg,bytes_this_page,datalen,flags; + struct iovec *iovp; + int s; + + if(scsi_debug & PRINTROUTINES) + printf("aha_scsi_cmd "); + /***********************************************\ + * get a ccb (mbox-out) to use. If the transfer * + * is from a buf (possibly from interrupt time) * + * then we can't allow it to sleep * + \***********************************************/ + flags = xs->flags; + if(!(flags & INUSE)) + { + printf("not in use!"); + Debugger(); + xs->flags |= INUSE; + } + if(flags & ITSDONE) + { + printf("Already done! check device retry code "); + Debugger(); + xs->flags &= ~ITSDONE; + } + if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ + if (!(ccb = aha_get_ccb(unit,flags))) + { + xs->error = XS_DRIVER_STUFFUP; + return(TRY_AGAIN_LATER); + } + + if (ccb->mbx->cmd != AHA_MBO_FREE) + printf("MBO not free\n"); + + /***********************************************\ + * Put all the arguments for the xfer in the ccb * + \***********************************************/ + ccb->xfer = xs; + if(flags & SCSI_RESET) + { + ccb->opcode = AHA_RESET_CCB; + } + else + { + /* can't use S/G if zero length */ + ccb->opcode = (xs->datalen? + AHA_INIT_SCAT_GATH_CCB + :AHA_INITIATOR_CCB); + } + ccb->target = xs->targ;; + ccb->data_out = 0; + ccb->data_in = 0; + ccb->lun = xs->lu; + ccb->scsi_cmd_length = xs->cmdlen; + ccb->req_sense_length = sizeof(ccb->scsi_sense); + + if((xs->datalen) && (!(flags & SCSI_RESET))) + { /* can use S/G only if not zero length */ + lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr ); + sg = ccb->scat_gath ; + seg = 0; + if(flags & SCSI_DATA_UIO) + { + iovp = ((struct uio *)xs->data)->uio_iov; + datalen = ((struct uio *)xs->data)->uio_iovcnt; + while ((datalen) && (seg < AHA_NSEG)) + { + lto3b(iovp->iov_base,&(sg->seg_addr)); + lto3b(iovp->iov_len,&(sg->seg_len)); + if(scsi_debug & SHOWSCATGATH) + printf("(0x%x@0x%x)" + ,iovp->iov_len + ,iovp->iov_base); + sg++; + iovp++; + seg++; + datalen--; + } + } + else + { + /***********************************************\ + * Set up the scatter gather block * + \***********************************************/ + + if(scsi_debug & SHOWSCATGATH) + printf("%d @0x%x:- ",xs->datalen,xs->data); + datalen = xs->datalen; + thiskv = (int)xs->data; + thisphys = KVTOPHYS(thiskv); + + while ((datalen) && (seg < AHA_NSEG)) + { + bytes_this_seg = 0; + + /* put in the base address */ + lto3b(thisphys,&(sg->seg_addr)); + + if(scsi_debug & SHOWSCATGATH) + printf("0x%x",thisphys); + + /* do it at least once */ + nextphys = thisphys; + while ((datalen) && (thisphys == nextphys)) + /***************************************\ + * This page is contiguous (physically) * + * with the the last, just extend the * + * length * + \***************************************/ + { + /** how far to the end of the page ***/ + nextphys = (thisphys & (~(PAGESIZ - 1))) + + PAGESIZ; + bytes_this_page = nextphys - thisphys; + /**** or the data ****/ + bytes_this_page = min(bytes_this_page + ,datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; + + /**** get more ready for the next page ****/ + thiskv = (thiskv & (~(PAGESIZ - 1))) + + PAGESIZ; + if(datalen) + thisphys = KVTOPHYS(thiskv); + } + /***************************************\ + * next page isn't contiguous, finish the seg* + \***************************************/ + if(scsi_debug & SHOWSCATGATH) + printf("(0x%x)",bytes_this_seg); + lto3b(bytes_this_seg,&(sg->seg_len)); + sg++; + seg++; + } + } + lto3b(seg * sizeof(struct aha_scat_gath),ccb->data_length); + if(scsi_debug & SHOWSCATGATH) + printf("\n"); + if (datalen) + { /* there's still data, must have run out of segs! */ + printf("aha_scsi_cmd%d: more than %d DMA segs\n", + unit,AHA_NSEG); + xs->error = XS_DRIVER_STUFFUP; + aha_free_ccb(unit,ccb,flags); + return(HAD_ERROR); + } + + } + else + { /* No data xfer, use non S/G values */ + lto3b(0, ccb->data_addr ); + lto3b(0,ccb->data_length); + } + lto3b(0, ccb->link_addr ); + /***********************************************\ + * Put the scsi command in the ccb and start it * + \***********************************************/ + if(!(flags & SCSI_RESET)) + bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length); + if(scsi_debug & SHOWCOMMANDS) + { + u_char *b = (u_char *)&ccb->scsi_cmd; + if(!(flags & SCSI_RESET)) + { + int i = 0; + printf("aha%d:%d:%d-" + ,unit + ,ccb->target + ,ccb->lun ); + while(i < ccb->scsi_cmd_length ) + { + if(i) printf(","); + printf("%x",b[i++]); + } + } + else + { + printf("aha%d:%d:%d-RESET- " + ,unit + ,ccb->target + ,ccb->lun + ); + } + } + if (!(flags & SCSI_NOMASK)) + { + s= splbio(); /* stop instant timeouts */ + aha_add_timeout(ccb,xs->timeout); + aha_startmbx(ccb->mbx); + /***********************************************\ + * Usually return SUCCESSFULLY QUEUED * + \***********************************************/ + splx(s); + if(scsi_debug & TRACEINTERRUPTS) + printf("sent "); + return(SUCCESSFULLY_QUEUED); + } + aha_startmbx(ccb->mbx); + if(scsi_debug & TRACEINTERRUPTS) + printf("cmd_sent, waiting "); + /***********************************************\ + * If we can't use interrupts, poll on completion* + \***********************************************/ + { + int done = 0; + int count = delaycount * xs->timeout / AHA_SCSI_TIMEOUT_FUDGE; + while((!done) && count) + { + i=0; + while ( (!done) && i<AHA_MBX_SIZE) + { + if ((aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE ) + && (PHYSTOKV(_3btol(aha_mbx[unit].mbi[i].ccb_addr) + == (int)ccb))) + { + aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE; + aha_done(unit,ccb); + done++; + } + i++; + } + count--; + } + if (!count) + { + if (!(xs->flags & SCSI_SILENT)) + printf("cmd fail\n"); + aha_abortmbx(ccb->mbx); + count = delaycount * 2000 / AHA_SCSI_TIMEOUT_FUDGE; + while((!done) && count) + { + i=0; + while ( (!done) && i<AHA_MBX_SIZE) + { + if ((aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE ) + && (PHYSTOKV(_3btol(aha_mbx[unit].mbi[i].ccb_addr) + == (int)ccb))) + { + aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE; + aha_done(unit,ccb); + done++; + } + i++; + } + count--; + } + if(!count) + { + printf("abort failed in wait\n"); + ccb->mbx->cmd = AHA_MBO_FREE; + } + aha_free_ccb(unit,ccb,flags); + ahaintr(unit); + xs->error = XS_DRIVER_STUFFUP; + return(HAD_ERROR); + } + ahaintr(unit); + if(xs->error) return(HAD_ERROR); + return(COMPLETE); + + } +} +/***************************************************************\ +* try each speed in turn, when we find one that works, use * +* the NEXT one for a safety margin, unless that doesn't exist * +* or doesn't work. returns the nSEC value of the time used * +* or 0 if it could get a working speed ( or the NEXT speed * +* failed) * +\***************************************************************/ + +int aha_set_bus_speed(unit) +int unit; +{ + int speed; + int retval,retval2; + +#ifdef EISA + speed = 0; /* start at the fastest */ +#else EISA + speed = 1; /* 100 ns can crash some ISA busses (!?!) */ +#endif EISA + while (1) + { + retval = aha_bus_speed_check(unit,speed); + if(retval == HAD_ERROR) + { + printf("no working bus speed!!!\n"); + return(0); + } + if(retval == 0) + { + speed++; + } + else /* Go one slower to be safe */ + { /* unless eisa at 100 ns.. trust it */ + if(speed != 0) + { + speed++; + } + printf("%d nSEC ok, use ",retval); + retval2 = aha_bus_speed_check(unit,speed); + if(retval2 == HAD_ERROR) /* retval is slowest already */ + { + printf("marginal "); + retval2 = retval; + } + if(retval2) + { + printf("%d nSEC ",retval2); + return(retval2); + } + else + { + printf(".. slower failed, abort.\n",retval); + return(0); + } + + } + } +} + +/***************************************************************\ +* Set the DMA speed to the Nth speed and try an xfer. If it * +* fails return 0, if it succeeds return the nSec value selected * +* If there is no such speed return HAD_ERROR. * +\***************************************************************/ +static struct bus_speed +{ + char arg; + int nsecs; +}aha_bus_speeds[] = +{ + {0x88,100}, + {0x99,150}, + {0xaa,200}, + {0xbb,250}, + {0xcc,300}, + {0xdd,350}, + {0xee,400}, + {0xff,450} +}; +static char aha_test_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@"; + +int aha_bus_speed_check(unit,speed) +int unit,speed; +{ + int numspeeds = sizeof(aha_bus_speeds)/sizeof(struct bus_speed); + u_char ad[3]; + + /*******************************************************\ + * Check we have such an entry * + \*******************************************************/ + if(speed >= numspeeds) return(HAD_ERROR); /* illegal speed */ + + /*******************************************************\ + * Set the dma-speed * + \*******************************************************/ + aha_cmd(unit,1, 0, 0, 0, AHA_SPEED_SET,aha_bus_speeds[speed].arg); + + /*******************************************************\ + * put the test data into the buffer and calculate * + * it's address. Read it onto the board * + \*******************************************************/ + strcpy(aha_scratch_buf,aha_test_string); + lto3b(KVTOPHYS(aha_scratch_buf),ad); + + aha_cmd(unit,3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]); + + /*******************************************************\ + * clear the buffer then copy the contents back from the * + * board. * + \*******************************************************/ + bzero(aha_scratch_buf,54); /* 54 bytes transfered by test */ + + aha_cmd(unit,3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]); + + /*******************************************************\ + * Compare the original data and the final data and * + * return the correct value depending upon the result * + \*******************************************************/ + if(strcmp(aha_test_string,aha_scratch_buf)) + { /* copy failed.. assume too fast */ + return(0); + } + else + { /* copy succeded assume speed ok */ + return(aha_bus_speeds[speed].nsecs); + } +} + + +/* + * +----------+ +----------+ +----------+ + * aha_soonest--->| later |--->| later|--->| later|-->0 + * | [Delta] | | [Delta] | | [Delta] | + * 0<---|sooner |<---|sooner |<---|sooner |<---aha_latest + * +----------+ +----------+ +----------+ + * + * aha_furtherest = sum(Delta[1..n]) + */ +aha_add_timeout(ccb,time) +struct aha_ccb *ccb; +int time; +{ + int timeprev; + struct aha_ccb *prev; + int s = splbio(); + + if(prev = aha_latest) /* yes, an assign */ + { + timeprev = aha_furtherest; + } + else + { + timeprev = 0; + } + while(prev && (timeprev > time)) + { + timeprev -= prev->delta; + prev = prev->sooner; + } + if(prev) + { + ccb->delta = time - timeprev; + if( ccb->later = prev->later) /* yes an assign */ + { + ccb->later->sooner = ccb; + ccb->later->delta -= ccb->delta; + } + else + { + aha_furtherest = time; + aha_latest = ccb; + } + ccb->sooner = prev; + prev->later = ccb; + } + else + { + if( ccb->later = aha_soonest) /* yes, an assign*/ + { + ccb->later->sooner = ccb; + ccb->later->delta -= time; + } + else + { + aha_furtherest = time; + aha_latest = ccb; + } + ccb->delta = time; + ccb->sooner = (struct aha_ccb *)0; + aha_soonest = ccb; + } + splx(s); +} + +aha_remove_timeout(ccb) +struct aha_ccb *ccb; +{ + int s = splbio(); + + if(ccb->sooner) + { + ccb->sooner->later = ccb->later; + } + else + { + aha_soonest = ccb->later; + } + if(ccb->later) + { + ccb->later->sooner = ccb->sooner; + ccb->later->delta += ccb->delta; + } + else + { + aha_latest = ccb->sooner; + aha_furtherest -= ccb->delta; + } + ccb->sooner = ccb->later = (struct aha_ccb *)0; + splx(s); +} + + +extern int hz; +#define ONETICK 500 /* milliseconds */ +#define SLEEPTIME ((hz * 1000) / ONETICK) +aha_timeout(arg) +int arg; +{ + struct aha_ccb *ccb; + int unit; + int s = splbio(); + + while( ccb = aha_soonest ) + { + if(ccb->delta <= ONETICK) + /***********************************************\ + * It has timed out, we need to do some work * + \***********************************************/ + { + unit = ccb->xfer->adapter; + printf("aha%d: device %d timed out ",unit + ,ccb->xfer->targ); + + /***************************************\ + * Unlink it from the queue * + \***************************************/ + aha_remove_timeout(ccb); + + /***************************************\ + * If The ccb's mbx is not free, then * + * the board has gone south * + \***************************************/ + if(ccb->mbx->cmd != AHA_MBO_FREE) + { + printf("aha%d not taking commands!\n" + ,unit); + Debugger(); + } + /***************************************\ + * If it has been through before, then * + * a previous abort has failed, don't * + * try abort again * + \***************************************/ + if(ccb->flags == CCB_ABORTED) /* abort timed out */ + { + printf(" AGAIN\n"); + ccb->xfer->retries = 0; /* I MEAN IT ! */ + ccb->host_stat = AHA_ABORTED; + aha_done(unit,ccb); + } + else /* abort the operation that has timed out */ + { + printf("\n"); + aha_abortmbx(ccb->mbx); + /* 2 secs for the abort */ + aha_add_timeout(ccb,2000 + ONETICK); + ccb->flags = CCB_ABORTED; + } + } + else + /***********************************************\ + * It has not timed out, adjust and leave * + \***********************************************/ + { + ccb->delta -= ONETICK; + aha_furtherest -= ONETICK; + break; + } + } + splx(s); + timeout(aha_timeout,arg,SLEEPTIME); +} diff --git a/sys/i386/isa/aha1742.c b/sys/i386/isa/aha1742.c new file mode 100644 index 000000000000..721f6f74b86f --- /dev/null +++ b/sys/i386/isa/aha1742.c @@ -0,0 +1,1420 @@ +/* + * Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * commenced: Sun Sep 27 18:14:01 PDT 1992 + */ + +#include <sys/types.h> +#include <ahb.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/user.h> + +#ifdef MACH /* EITHER CMU OR OSF */ +#include <i386/ipl.h> +#include <i386at/scsi.h> +#include <i386at/scsiconf.h> + +#ifdef OSF /* OSF ONLY */ +#include <sys/table.h> +#include <i386/handler.h> +#include <i386/dispatcher.h> +#include <i386/AT386/atbus.h> + +#else OSF /* CMU ONLY */ +#include <i386at/atbus.h> +#include <i386/pio.h> +#endif OSF +#endif MACH /* end of MACH specific */ + +#ifdef __386BSD__ /* 386BSD specific */ +#define isa_dev isa_device +#define dev_unit id_unit +#define dev_addr id_iobase + +#include <i386/include/pio.h> +#include <i386/isa/isa_device.h> +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> +#endif __386BSD__ + +/**/ + +#ifdef __386BSD__ +#include "ddb.h" +#if NDDB > 0 +int Debugger(); +#else NDDB +#define Debugger() panic("should call debugger here (adaptec.c)") +#endif NDDB +#endif __386BSD__ + +#ifdef MACH +int Debugger(); +#endif MACH + +typedef unsigned long int physaddr; + +#ifdef MACH +extern physaddr kvtophys(); +#define PHYSTOKV(x) phystokv(x) +#define KVTOPHYS(x) kvtophys(x) +#endif MACH + +#ifdef __386BSD__ +#define PHYSTOKV(x) (x | 0xFE000000) +#define KVTOPHYS(x) vtophys(x) +#endif __386BSD__ + +extern int delaycount; /* from clock setup code */ +#define NUM_CONCURRENT 16 /* number of concurrent ops per board */ +#define AHB_NSEG 33 /* number of dma segments supported */ +#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */ +/**/ +/***********************************************************************\ +* AHA1740 standard EISA Host ID regs (Offset from slot base) * +\***********************************************************************/ +#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */ +#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */ +#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */ +#define HID3 0xC83 /* firmware revision */ + +#define CHAR1(B1,B2) (((B1>>2) & 0x1F) | '@') +#define CHAR2(B1,B2) (((B1<<3) & 0x18) | ((B2>>5) & 0x7)|'@') +#define CHAR3(B1,B2) ((B2 & 0x1F) | '@') + +/* AHA1740 EISA board control registers (Offset from slot base) */ +#define EBCTRL 0xC84 +#define CDEN 0x01 +/***********************************************************************\ +* AHA1740 EISA board mode registers (Offset from slot base) * +\***********************************************************************/ +#define PORTADDR 0xCC0 +#define PORTADDR_ENHANCED 0x80 +#define BIOSADDR 0xCC1 +#define INTDEF 0xCC2 +#define SCSIDEF 0xCC3 +#define BUSDEF 0xCC4 +#define RESV0 0xCC5 +#define RESV1 0xCC6 +#define RESV2 0xCC7 +/**** bit definitions for INTDEF ****/ +#define INT9 0x00 +#define INT10 0x01 +#define INT11 0x02 +#define INT12 0x03 +#define INT14 0x05 +#define INT15 0x06 +#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */ +#define INTEN 0x10 +/**** bit definitions for SCSIDEF ****/ +#define HSCSIID 0x0F /* our SCSI ID */ +#define RSTPWR 0x10 /* reset scsi bus on power up or reset */ +/**** bit definitions for BUSDEF ****/ +#define B0uS 0x00 /* give up bus immediatly */ +#define B4uS 0x01 /* delay 4uSec. */ +#define B8uS 0x02 +/***********************************************************************\ +* AHA1740 ENHANCED mode mailbox control regs (Offset from slot base) * +\***********************************************************************/ +#define MBOXOUT0 0xCD0 +#define MBOXOUT1 0xCD1 +#define MBOXOUT2 0xCD2 +#define MBOXOUT3 0xCD3 + +#define ATTN 0xCD4 +#define G2CNTRL 0xCD5 +#define G2INTST 0xCD6 +#define G2STAT 0xCD7 + +#define MBOXIN0 0xCD8 +#define MBOXIN1 0xCD9 +#define MBOXIN2 0xCDA +#define MBOXIN3 0xCDB + +#define G2STAT2 0xCDC + +/*******************************************************\ +* Bit definitions for the 5 control/status registers * +\*******************************************************/ +#define ATTN_TARGET 0x0F +#define ATTN_OPCODE 0xF0 +#define OP_IMMED 0x10 +#define AHB_TARG_RESET 0x80 +#define OP_START_ECB 0x40 +#define OP_ABORT_ECB 0x50 + +#define G2CNTRL_SET_HOST_READY 0x20 +#define G2CNTRL_CLEAR_EISA_INT 0x40 +#define G2CNTRL_HARD_RESET 0x80 + +#define G2INTST_TARGET 0x0F +#define G2INTST_INT_STAT 0xF0 +#define AHB_ECB_OK 0x10 +#define AHB_ECB_RECOVERED 0x50 +#define AHB_HW_ERR 0x70 +#define AHB_IMMED_OK 0xA0 +#define AHB_ECB_ERR 0xC0 +#define AHB_ASN 0xD0 /* for target mode */ +#define AHB_IMMED_ERR 0xE0 + +#define G2STAT_BUSY 0x01 +#define G2STAT_INT_PEND 0x02 +#define G2STAT_MBOX_EMPTY 0x04 + +#define G2STAT2_HOST_READY 0x01 +/**/ + +struct ahb_dma_seg +{ + physaddr addr; + long len; +}; + +struct ahb_ecb_status +{ + u_short status; +# define ST_DON 0x0001 +# define ST_DU 0x0002 +# define ST_QF 0x0008 +# define ST_SC 0x0010 +# define ST_DO 0x0020 +# define ST_CH 0x0040 +# define ST_INT 0x0080 +# define ST_ASA 0x0100 +# define ST_SNS 0x0200 +# define ST_INI 0x0800 +# define ST_ME 0x1000 +# define ST_ECA 0x4000 + u_char ha_status; +# define HS_OK 0x00 +# define HS_CMD_ABORTED_HOST 0x04 +# define HS_CMD_ABORTED_ADAPTER 0x05 +# define HS_TIMED_OUT 0x11 +# define HS_HARDWARE_ERR 0x20 +# define HS_SCSI_RESET_ADAPTER 0x22 +# define HS_SCSI_RESET_INCOMING 0x23 + u_char targ_status; +# define TS_OK 0x00 +# define TS_CHECK_CONDITION 0x02 +# define TS_BUSY 0x08 + u_long resid_count; + u_long resid_addr; + u_short addit_status; + u_char sense_len; + u_char unused[9]; + u_char cdb[6]; +}; + +/**/ + +struct ecb +{ + u_char opcode; +# define ECB_SCSI_OP 0x01 + u_char :4; + u_char options:3; + u_char :1; + short opt1; +# define ECB_CNE 0x0001 +# define ECB_DI 0x0080 +# define ECB_SES 0x0400 +# define ECB_S_G 0x1000 +# define ECB_DSB 0x4000 +# define ECB_ARS 0x8000 + short opt2; +# define ECB_LUN 0x0007 +# define ECB_TAG 0x0008 +# define ECB_TT 0x0030 +# define ECB_ND 0x0040 +# define ECB_DAT 0x0100 +# define ECB_DIR 0x0200 +# define ECB_ST 0x0400 +# define ECB_CHK 0x0800 +# define ECB_REC 0x4000 +# define ECB_NRB 0x8000 + u_short unused1; + physaddr data; + u_long datalen; + physaddr status; + physaddr chain; + short unused2; + short unused3; + physaddr sense; + u_char senselen; + u_char cdblen; + short cksum; + u_char cdb[12]; + /*-----------------end of hardware supported fields----------------*/ + struct ecb *next; /* in free list */ + struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ + long int delta; /* difference from previous*/ + struct ecb *later,*sooner; + int flags; +#define ECB_FREE 0 +#define ECB_ACTIVE 1 +#define ECB_ABORTED 2 +#define ECB_IMMED 4 +#define ECB_IMMED_FAIL 8 + struct ahb_dma_seg ahb_dma[AHB_NSEG]; + struct ahb_ecb_status ecb_status; + struct scsi_sense_data ecb_sense; +}; + +struct ecb *ahb_soonest = (struct ecb *)0; +struct ecb *ahb_latest = (struct ecb *)0; +long int ahb_furtherest = 0; /* longest time in the timeout queue */ +/**/ + +struct ahb_data +{ + int flags; +#define AHB_INIT 0x01; + int baseport; + struct ecb ecbs[NUM_CONCURRENT]; + struct ecb *free_ecb; + int our_id; /* our scsi id */ + int vect; + struct ecb *immed_ecb; /* an outstanding immediete command */ +} ahb_data[NAHB]; + +int ahbprobe(); +int ahb_attach(); +int ahbintr(); +int ahb_scsi_cmd(); +int ahb_timeout(); +struct ecb *cheat; +void ahbminphys(); +long int ahb_adapter_info(); + +#ifdef MACH +struct isa_driver ahbdriver = { ahbprobe, 0, ahb_attach, "ahb", 0, 0, 0}; +int (*ahbintrs[])() = {ahbintr, 0}; +#endif MACH + +#ifdef __386BSD__ +struct isa_driver ahbdriver = { ahbprobe, ahb_attach, "ahb"}; +#endif __386BSD__ + +#define MAX_SLOTS 8 +static ahb_slot = 0; /* slot last board was found in */ +static ahb_unit = 0; +int ahb_debug = 0; +#define AHB_SHOWECBS 0x01 +#define AHB_SHOWINTS 0x02 +#define AHB_SHOWCMDS 0x04 +#define AHB_SHOWMISC 0x08 +#define FAIL 1 +#define SUCCESS 0 +#define PAGESIZ 4096 + +struct scsi_switch ahb_switch = +{ + ahb_scsi_cmd, + ahbminphys, + 0, + 0, + ahb_adapter_info, + 0,0,0 +}; + +/**/ +/***********************************************************************\ +* Function to send a command out through a mailbox * +\***********************************************************************/ +ahb_send_mbox( int unit + ,int opcode + ,int target + ,struct ecb *ecb) +{ + int port = ahb_data[unit].baseport; + int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ + int s = splbio(); + int stport = port + G2STAT; + + while( ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) + != (G2STAT_MBOX_EMPTY)) + && (spincount--)); + if(spincount == -1) + { + printf("ahb%d: board not responding\n",unit); + Debugger(); + } + + outl(port + MBOXOUT0,KVTOPHYS(ecb)); /* don't know this will work */ + outb(port + ATTN, opcode|target); + + splx(s); +} + +/***********************************************************************\ +* Function to poll for command completion when in poll mode * +\***********************************************************************/ +ahb_poll(int unit ,int wait) /* in msec */ +{ + int port = ahb_data[unit].baseport; + int spincount = FUDGE(delaycount) * wait; /* in msec */ + int stport = port + G2STAT; +int start = spincount; + +retry: + while( (spincount--) && (!(inb(stport) & G2STAT_INT_PEND))); + if(spincount == -1) + { + printf("ahb%d: board not responding\n",unit); + return(EIO); + } +if ((int)cheat != PHYSTOKV(inl(port + MBOXIN0))) +{ + printf("discarding %x ",inl(port + MBOXIN0)); + outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); + spinwait(50); + goto retry; +}/* don't know this will work */ + ahbintr(unit); + return(0); +} +/***********************************************************************\ +* Function to send an immediate type command to the adapter * +\***********************************************************************/ +ahb_send_immed( int unit + ,int target + ,u_long cmd) +{ + int port = ahb_data[unit].baseport; + int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ + int s = splbio(); + int stport = port + G2STAT; + + while( ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) + != (G2STAT_MBOX_EMPTY)) + && (spincount--)); + if(spincount == -1) + { + printf("ahb%d: board not responding\n",unit); + Debugger(); + } + + outl(port + MBOXOUT0,cmd); /* don't know this will work */ + outb(port + G2CNTRL, G2CNTRL_SET_HOST_READY); + outb(port + ATTN, OP_IMMED | target); + splx(s); +} + +/**/ + +/*******************************************************\ +* Check the slots looking for a board we recognise * +* If we find one, note it's address (slot) and call * +* the actual probe routine to check it out. * +\*******************************************************/ +ahbprobe(dev) +struct isa_dev *dev; +{ + int port; + u_char byte1,byte2,byte3; + ahb_slot++; + while (ahb_slot<8) + { + port = 0x1000 * ahb_slot; + byte1 = inb(port + HID0); + byte2 = inb(port + HID1); + byte3 = inb(port + HID2); + if(byte1 == 0xff) + { + ahb_slot++; + continue; + } + if ((CHAR1(byte1,byte2) == 'A') + && (CHAR2(byte1,byte2) == 'D') + && (CHAR3(byte1,byte2) == 'P') + && ((byte3 == 0 ) || (byte3 == 1))) + { + dev->dev_addr = port; + return(ahbprobe1(dev)); + } + ahb_slot++; + } + return(0); +} +/*******************************************************\ +* Check if the device can be found at the port given * +* and if so, set it up ready for further work * +* as an argument, takes the isa_dev structure from * +* autoconf.c * +\*******************************************************/ +ahbprobe1(dev) +struct isa_dev *dev; +{ + /***********************************************\ + * find unit and check we have that many defined * + \***********************************************/ + int unit = ahb_unit; +#if defined(OSF) + static ihandler_t ahb_handler[NAHB]; + static ihandler_id_t *ahb_handler_id[NAHB]; + register ihandler_t *chp = &ahb_handler[unit];; +#endif /* defined(OSF) */ + + dev->dev_unit = unit; + ahb_data[unit].baseport = dev->dev_addr; + if(unit >= NAHB) + { + printf("ahb: unit number (%d) too high\n",unit); + return(0); + } + /***********************************************\ + * Try initialise a unit at this location * + * sets up dma and bus speed, loads ahb_data[unit].vect* + \***********************************************/ + if (ahb_init(unit) != 0) + { + return(0); + } + + /***********************************************\ + * If it's there, put in it's interrupt vectors * + \***********************************************/ +#ifdef MACH +#if defined(OSF) /* OSF */ + chp->ih_level = dev->dev_pic; + chp->ih_handler = dev->dev_intr[0]; + chp->ih_resolver = i386_resolver; + chp->ih_rdev = dev; + chp->ih_stats.intr_type = INTR_DEVICE; + chp->ih_stats.intr_cnt = 0; + chp->ih_hparam[0].intparam = unit; + if ((ahb_handler_id[unit] = handler_add(chp)) != NULL) + handler_enable(ahb_handler_id[unit]); + else + panic("Unable to add ahb interrupt handler"); +#else /* CMU */ + dev->dev_pic = ahb_data[unit].vect; + take_dev_irq(dev); +#endif /* !defined(OSF) */ + printf("port=%x spl=%d\n", dev->dev_addr, dev->dev_spl); +#endif MACH +#ifdef __386BSD__ /* 386BSD */ + dev->id_irq = (1 << ahb_data[unit].vect); + dev->id_drq = -1; /* use EISA dma */ + printf("\n **"); +#endif __386BSD__ + + ahb_unit++; + return(1); +} + +/***********************************************\ +* Attach all the sub-devices we can find * +\***********************************************/ +ahb_attach(dev) +struct isa_dev *dev; +{ + int unit = dev->dev_unit; + + +#ifdef __386BSD__ + printf(" probing for scsi devices**\n"); +#endif __386BSD__ + + /***********************************************\ + * ask the adapter what subunits are present * + \***********************************************/ + scsi_attachdevs( unit, ahb_data[unit].our_id, &ahb_switch); +#if defined(OSF) + ahb_attached[unit]=1; +#endif /* defined(OSF) */ + if(!unit) /* only one for all boards */ + { + ahb_timeout(0); + } +#ifdef __386BSD__ + printf("ahb%d",unit); +#endif __386BSD__ + return; +} + +/***********************************************\ +* Return some information to the caller about * +* the adapter and it's capabilities * +\***********************************************/ +long int ahb_adapter_info(unit) +int unit; +{ + return(2); /* 2 outstanding requests at a time per device */ +} + +/***********************************************\ +* Catch an interrupt from the adaptor * +\***********************************************/ +ahbintr(unit) +{ + struct ecb *ecb; + unsigned char stat; + register i; + u_char ahbstat; + int target; + long int mboxval; + + int port = ahb_data[unit].baseport; + + if(scsi_debug & PRINTROUTINES) + printf("ahbintr "); + +#if defined(OSF) + if (!ahb_attached[unit]) + { + return(1); + } +#endif /* defined(OSF) */ + while(inb(port + G2STAT) & G2STAT_INT_PEND) + { + /***********************************************\ + * First get all the information and then * + * acknowlege the interrupt * + \***********************************************/ + ahbstat = inb(port + G2INTST); + target = ahbstat & G2INTST_TARGET; + stat = ahbstat & G2INTST_INT_STAT; + mboxval = inl(port + MBOXIN0);/* don't know this will work */ + outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); + if(scsi_debug & TRACEINTERRUPTS) + printf("status = 0x%x ",stat); + /***********************************************\ + * Process the completed operation * + \***********************************************/ + + if(stat == AHB_ECB_OK) /* common case is fast */ + { + ecb = (struct ecb *)PHYSTOKV(mboxval); + } + else + { + switch(stat) + { + case AHB_IMMED_OK: + ecb = ahb_data[unit].immed_ecb; + ahb_data[unit].immed_ecb = 0; + break; + case AHB_IMMED_ERR: + ecb = ahb_data[unit].immed_ecb; + ecb->flags |= ECB_IMMED_FAIL; + ahb_data[unit].immed_ecb = 0; + break; + case AHB_ASN: /* for target mode */ + ecb = 0; + break; + case AHB_HW_ERR: + ecb = 0; + break; + case AHB_ECB_RECOVERED: + ecb = (struct ecb *)PHYSTOKV(mboxval); + break; + case AHB_ECB_ERR: + ecb = (struct ecb *)PHYSTOKV(mboxval); + break; + default: + printf(" Unknown return from ahb%d(%x)\n",unit,ahbstat); + ecb=0; + } + } + if(ecb) + { + if(ahb_debug & AHB_SHOWCMDS ) + { + ahb_show_scsi_cmd(ecb->xs); + } + if((ahb_debug & AHB_SHOWECBS) && ecb) + printf("<int ecb(%x)>",ecb); + ahb_remove_timeout(ecb); + ahb_done(unit,ecb,((stat == AHB_ECB_OK)?SUCCESS:FAIL)); + } + } + return(1); +} + +/***********************************************\ +* We have a ecb which has been processed by the * +* adaptor, now we look to see how the operation * +* went. * +\***********************************************/ +ahb_done(unit,ecb,state) +int unit,state; +struct ecb *ecb; +{ + struct ahb_ecb_status *stat = &ecb->ecb_status; + struct scsi_sense_data *s1,*s2; + struct scsi_xfer *xs = ecb->xs; + + if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) + printf("ahb_done "); + /***********************************************\ + * Otherwise, put the results of the operation * + * into the xfer and call whoever started it * + \***********************************************/ + if(ecb->flags & ECB_IMMED) + { + if(ecb->flags & ECB_IMMED_FAIL) + { + xs->error = XS_DRIVER_STUFFUP; + } + goto done; + } + if ( (state == SUCCESS) || (xs->flags & SCSI_ERR_OK)) + { /* All went correctly OR errors expected */ + xs->resid = 0; + xs->error = 0; + } + else + { + + s1 = &(ecb->ecb_sense); + s2 = &(xs->sense); + + if(stat->ha_status) + { + switch(stat->ha_status) + { + case HS_SCSI_RESET_ADAPTER: + break; + case HS_SCSI_RESET_INCOMING: + break; + case HS_CMD_ABORTED_HOST: /* No response */ + case HS_CMD_ABORTED_ADAPTER: /* No response */ + break; + case HS_TIMED_OUT: /* No response */ + if (ahb_debug & AHB_SHOWMISC) + { + printf("timeout reported back\n"); + } + xs->error = XS_TIMEOUT; + break; + default: /* Other scsi protocol messes */ + xs->error = XS_DRIVER_STUFFUP; + if (ahb_debug & AHB_SHOWMISC) + { + printf("unexpected ha_status: %x\n", + stat->ha_status); + } + } + + } + else + { + switch(stat->targ_status) + { + case TS_CHECK_CONDITION: + /* structure copy!!!!!*/ + *s2=*s1; + xs->error = XS_SENSE; + break; + case TS_BUSY: + xs->error = XS_BUSY; + break; + default: + if (ahb_debug & AHB_SHOWMISC) + { + printf("unexpected targ_status: %x\n", + stat->targ_status); + } + xs->error = XS_DRIVER_STUFFUP; + } + } + } +done: xs->flags |= ITSDONE; + ahb_free_ecb(unit,ecb, xs->flags); + if(xs->when_done) + (*(xs->when_done))(xs->done_arg,xs->done_arg2); +} + +/***********************************************\ +* A ecb (and hence a mbx-out is put onto the * +* free list. * +\***********************************************/ +ahb_free_ecb(unit,ecb, flags) +struct ecb *ecb; +{ + unsigned int opri; + + if(scsi_debug & PRINTROUTINES) + printf("ecb%d(0x%x)> ",unit,flags); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + + ecb->next = ahb_data[unit].free_ecb; + ahb_data[unit].free_ecb = ecb; + ecb->flags = ECB_FREE; + /***********************************************\ + * If there were none, wake abybody waiting for * + * one to come free, starting with queued entries* + \***********************************************/ + if (!ecb->next) { + wakeup(&ahb_data[unit].free_ecb); + } + if (!(flags & SCSI_NOMASK)) + splx(opri); +} + +/***********************************************\ +* Get a free ecb (and hence mbox-out entry) * +\***********************************************/ +struct ecb * +ahb_get_ecb(unit,flags) +{ + unsigned opri; + struct ecb *rc; + + if(scsi_debug & PRINTROUTINES) + printf("<ecb%d(0x%x) ",unit,flags); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + /***********************************************\ + * If we can and have to, sleep waiting for one * + * to come free * + \***********************************************/ + while ((!(rc = ahb_data[unit].free_ecb)) && (!(flags & SCSI_NOSLEEP))) + { + sleep(&ahb_data[unit].free_ecb, PRIBIO); + } + if (rc) + { + ahb_data[unit].free_ecb = rc->next; + rc->flags = ECB_ACTIVE; + } + if (!(flags & SCSI_NOMASK)) + splx(opri); + return(rc); +} + + + +/***********************************************\ +* Start the board, ready for normal operation * +\***********************************************/ +ahb_init(unit) +int unit; +{ + int port = ahb_data[unit].baseport; + int intdef; + int spincount = FUDGE(delaycount) * 1000; /* 1 sec enough? */ + int i; + int stport = port + G2STAT; +#define NO_NO 1 +#ifdef NO_NO + /***********************************************\ + * reset board, If it doesn't respond, assume * + * that it's not there.. good for the probe * + \***********************************************/ + outb(port + EBCTRL,CDEN); /* enable full card */ + outb(port + PORTADDR,PORTADDR_ENHANCED); + + outb(port + G2CNTRL,G2CNTRL_HARD_RESET); + spinwait(1); + outb(port + G2CNTRL,0); + spinwait(10); + while( ((inb(stport) & G2STAT_BUSY )) + && (spincount--)); + if(spincount == -1) + { + if (ahb_debug & AHB_SHOWMISC) + printf("ahb_init: No answer from bt742a board\n"); + return(ENXIO); + } + i = inb(port + MBOXIN0) & 0xff; + if(i) + { + printf("self test failed, val = 0x%x\n",i); + return(EIO); + } +#endif + while( inb(stport) & G2STAT_INT_PEND) + { + printf("."); + outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); + spinwait(10); + } + outb(port + EBCTRL,CDEN); /* enable full card */ + outb(port + PORTADDR,PORTADDR_ENHANCED); + /***********************************************\ + * Assume we have a board at this stage * + * setup dma channel from jumpers and save int * + * level * + \***********************************************/ +#ifdef __386BSD__ + printf("ahb%d reading board settings, ",unit); +#define PRNT(x) +#else __386BSD__ + printf("ahb%d:",unit); +#define PRNT(x) printf(x) +#endif __386BSD__ + + intdef = inb(port + INTDEF); + switch(intdef & 0x07) + { + case INT9: + ahb_data[unit].vect = 9; + PRNT("int=9 "); + break; + case INT10: + ahb_data[unit].vect = 10; + PRNT("int=10 "); + break; + case INT11: + ahb_data[unit].vect = 11; + PRNT("int=11 "); + break; + case INT12: + ahb_data[unit].vect = 12; + PRNT("int=12 "); + break; + case INT14: + ahb_data[unit].vect = 14; + PRNT("int=14 "); + break; + case INT15: + ahb_data[unit].vect = 15; + PRNT("int=15 "); + break; + default: + printf("illegal int setting\n"); + return(EIO); + } + outb(port + INTDEF ,(intdef | INTEN)); /* make sure we can interrupt */ + /* who are we on the scsi bus */ + ahb_data[unit].our_id = (inb(port + SCSIDEF) & HSCSIID); + + /***********************************************\ + * link up all our ECBs into a free list * + \***********************************************/ + for (i=0; i < NUM_CONCURRENT; i++) + { + ahb_data[unit].ecbs[i].next = ahb_data[unit].free_ecb; + ahb_data[unit].free_ecb = &ahb_data[unit].ecbs[i]; + ahb_data[unit].free_ecb->flags = ECB_FREE; + } + + /***********************************************\ + * Note that we are going and return (to probe) * + \***********************************************/ + ahb_data[unit].flags |= AHB_INIT; + return( 0 ); +} + + +#ifndef min +#define min(x,y) (x < y ? x : y) +#endif min + + +void ahbminphys(bp) +struct buf *bp; +{ +#ifdef MACH +#if !defined(OSF) + bp->b_flags |= B_NPAGES; /* can support scat/gather */ +#endif /* defined(OSF) */ +#endif MACH + if(bp->b_bcount > ((AHB_NSEG-1) * PAGESIZ)) + { + bp->b_bcount = ((AHB_NSEG-1) * PAGESIZ); + } +} + +/***********************************************\ +* start a scsi operation given the command and * +* the data address. Also needs the unit, target * +* and lu * +\***********************************************/ +int ahb_scsi_cmd(xs) +struct scsi_xfer *xs; +{ + struct scsi_sense_data *s1,*s2; + struct ecb *ecb; + struct ahb_dma_seg *sg; + int seg; /* scatter gather seg being worked on */ + int i = 0; + int rc = 0; + int thiskv; + physaddr thisphys,nextphys; + int unit =xs->adapter; + int bytes_this_seg,bytes_this_page,datalen,flags; + struct iovec *iovp; + int s; + if(scsi_debug & PRINTROUTINES) + printf("ahb_scsi_cmd "); + /***********************************************\ + * get a ecb (mbox-out) to use. If the transfer * + * is from a buf (possibly from interrupt time) * + * then we can't allow it to sleep * + \***********************************************/ + flags = xs->flags; + if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ + if(flags & ITSDONE) + { + printf("Already done?"); + xs->flags &= ~ITSDONE; + } + if(!(flags & INUSE)) + { + printf("Not in use?"); + xs->flags |= INUSE; + } + if (!(ecb = ahb_get_ecb(unit,flags))) + { + xs->error = XS_DRIVER_STUFFUP; + return(TRY_AGAIN_LATER); + } + +cheat = ecb; + if(ahb_debug & AHB_SHOWECBS) + printf("<start ecb(%x)>",ecb); + if(scsi_debug & SHOWCOMMANDS) + { + ahb_show_scsi_cmd(xs); + } + ecb->xs = xs; + /***********************************************\ + * If it's a reset, we need to do an 'immediate' * + * command, and store it's ccb for later * + * if there is already an immediate waiting, * + * then WE must wait * + \***********************************************/ + if(flags & SCSI_RESET) + { + ecb->flags |= ECB_IMMED; + if(ahb_data[unit].immed_ecb) + { + return(TRY_AGAIN_LATER); + } + ahb_data[unit].immed_ecb = ecb; + if (!(flags & SCSI_NOMASK)) + { + s = splbio(); + ahb_send_immed(unit,xs->targ,AHB_TARG_RESET); + ahb_add_timeout(ecb,xs->timeout); + splx(s); + return(SUCCESSFULLY_QUEUED); + } + else + { + ahb_send_immed(unit,xs->targ,AHB_TARG_RESET); + /***********************************************\ + * If we can't use interrupts, poll on completion* + \***********************************************/ + if(scsi_debug & TRACEINTERRUPTS) + printf("wait "); + if( ahb_poll(unit,xs->timeout)) + { + ahb_free_ecb(unit,ecb,flags); + xs->error = XS_TIMEOUT; + return(HAD_ERROR); + } + return(COMPLETE); + } + } + /***********************************************\ + * Put all the arguments for the xfer in the ecb * + \***********************************************/ + ecb->opcode = ECB_SCSI_OP; + ecb->opt1 = ECB_SES|ECB_DSB|ECB_ARS; + if(xs->datalen) + { + ecb->opt1 |= ECB_S_G; + } + ecb->opt2 = xs->lu | ECB_NRB; + ecb->cdblen = xs->cmdlen; + ecb->sense = KVTOPHYS(&(ecb->ecb_sense)); + ecb->senselen = sizeof(ecb->ecb_sense); + ecb->status = KVTOPHYS(&(ecb->ecb_status)); + + if(xs->datalen) + { /* should use S/G only if not zero length */ + ecb->data = KVTOPHYS(ecb->ahb_dma); + sg = ecb->ahb_dma ; + seg = 0; + if(flags & SCSI_DATA_UIO) + { + iovp = ((struct uio *)xs->data)->uio_iov; + datalen = ((struct uio *)xs->data)->uio_iovcnt; + xs->datalen = 0; + while ((datalen) && (seg < AHB_NSEG)) + { + sg->addr = (physaddr)iovp->iov_base; + xs->datalen += sg->len = iovp->iov_len; + if(scsi_debug & SHOWSCATGATH) + printf("(0x%x@0x%x)" + ,iovp->iov_len + ,iovp->iov_base); + sg++; + iovp++; + seg++; + datalen--; + } + } + else + { + /***********************************************\ + * Set up the scatter gather block * + \***********************************************/ + + if(scsi_debug & SHOWSCATGATH) + printf("%d @0x%x:- ",xs->datalen,xs->data); + datalen = xs->datalen; + thiskv = (int)xs->data; + thisphys = KVTOPHYS(thiskv); + + while ((datalen) && (seg < AHB_NSEG)) + { + bytes_this_seg = 0; + + /* put in the base address */ + sg->addr = thisphys; + + if(scsi_debug & SHOWSCATGATH) + printf("0x%x",thisphys); + + /* do it at least once */ + nextphys = thisphys; + while ((datalen) && (thisphys == nextphys)) + /*********************************************\ + * This page is contiguous (physically) with * + * the the last, just extend the length * + \*********************************************/ + { + /* how far to the end of the page */ + nextphys= (thisphys & (~(PAGESIZ - 1))) + + PAGESIZ; + bytes_this_page = nextphys - thisphys; + /**** or the data ****/ + bytes_this_page = min(bytes_this_page + ,datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; + + /* get more ready for the next page */ + thiskv = (thiskv & (~(PAGESIZ - 1))) + + PAGESIZ; + if(datalen) + thisphys = KVTOPHYS(thiskv); + } + /********************************************\ + * next page isn't contiguous, finish the seg * + \********************************************/ + if(scsi_debug & SHOWSCATGATH) + printf("(0x%x)",bytes_this_seg); + sg->len = bytes_this_seg; + sg++; + seg++; + } + } /*end of iov/kv decision */ + ecb->datalen = seg * sizeof(struct ahb_dma_seg); + if(scsi_debug & SHOWSCATGATH) + printf("\n"); + if (datalen) + { /* there's still data, must have run out of segs! */ + printf("ahb_scsi_cmd%d: more than %d DMA segs\n", + unit,AHB_NSEG); + xs->error = XS_DRIVER_STUFFUP; + ahb_free_ecb(unit,ecb,flags); + return(HAD_ERROR); + } + + } + else + { /* No data xfer, use non S/G values */ + ecb->data = (physaddr)0; + ecb->datalen = 0; + } + ecb->chain = (physaddr)0; + /***********************************************\ + * Put the scsi command in the ecb and start it * + \***********************************************/ + bcopy(xs->cmd, ecb->cdb, xs->cmdlen); + /***********************************************\ + * Usually return SUCCESSFULLY QUEUED * + \***********************************************/ + if (!(flags & SCSI_NOMASK)) + { + s = splbio(); + ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb); + ahb_add_timeout(ecb,xs->timeout); + splx(s); + if(scsi_debug & TRACEINTERRUPTS) + printf("cmd_sent "); + return(SUCCESSFULLY_QUEUED); + } + /***********************************************\ + * If we can't use interrupts, poll on completion* + \***********************************************/ + ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb); + if(scsi_debug & TRACEINTERRUPTS) + printf("cmd_wait "); + do + { + if(ahb_poll(unit,xs->timeout)) + { + if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n"); + ahb_send_mbox(unit,OP_ABORT_ECB,xs->targ,ecb); + if(ahb_poll(unit,2000)) + { + printf("abort failed in wait\n"); + ahb_free_ecb(unit,ecb,flags); + } + xs->error = XS_DRIVER_STUFFUP; + splx(s); + return(HAD_ERROR); + } + } while (!(xs->flags & ITSDONE));/* something (?) else finished */ + splx(s); +scsi_debug = 0;ahb_debug = 0; + if(xs->error) + { + return(HAD_ERROR); + } + return(COMPLETE); +} + +/* + * +----------+ +----------+ +----------+ + * ahb_soonest--->| later |--->| later|--->| later|--->0 + * | [Delta] | | [Delta] | | [Delta] | + * 0<---|sooner |<---|sooner |<---|sooner |<---ahb_latest + * +----------+ +----------+ +----------+ + * + * ahb_furtherest = sum(Delta[1..n]) + */ +ahb_add_timeout(ecb,time) +struct ecb *ecb; +int time; +{ + int timeprev; + struct ecb *prev; + int s = splbio(); + + if(prev = ahb_latest) /* yes, an assign */ + { + timeprev = ahb_furtherest; + } + else + { + timeprev = 0; + } + while(prev && (timeprev > time)) + { + timeprev -= prev->delta; + prev = prev->sooner; + } + if(prev) + { + ecb->delta = time - timeprev; + if( ecb->later = prev->later) /* yes an assign */ + { + ecb->later->sooner = ecb; + ecb->later->delta -= ecb->delta; + } + else + { + ahb_furtherest = time; + ahb_latest = ecb; + } + ecb->sooner = prev; + prev->later = ecb; + } + else + { + if( ecb->later = ahb_soonest) /* yes, an assign*/ + { + ecb->later->sooner = ecb; + ecb->later->delta -= time; + } + else + { + ahb_furtherest = time; + ahb_latest = ecb; + } + ecb->delta = time; + ecb->sooner = (struct ecb *)0; + ahb_soonest = ecb; + } + splx(s); +} + +ahb_remove_timeout(ecb) +struct ecb *ecb; +{ + int s = splbio(); + + if(ecb->sooner) + { + ecb->sooner->later = ecb->later; + } + else + { + ahb_soonest = ecb->later; + } + if(ecb->later) + { + ecb->later->sooner = ecb->sooner; + ecb->later->delta += ecb->delta; + } + else + { + ahb_latest = ecb->sooner; + ahb_furtherest -= ecb->delta; + } + ecb->sooner = ecb->later = (struct ecb *)0; + splx(s); +} + + +extern int hz; +#define ONETICK 500 /* milliseconds */ +#define SLEEPTIME ((hz * 1000) / ONETICK) +ahb_timeout(arg) +int arg; +{ + struct ecb *ecb; + int unit; + int s = splbio(); + + while( ecb = ahb_soonest ) + { + if(ecb->delta <= ONETICK) + /***********************************************\ + * It has timed out, we need to do some work * + \***********************************************/ + { + unit = ecb->xs->adapter; + printf("ahb%d:%d device timed out\n",unit + ,ecb->xs->targ); + if(ahb_debug & AHB_SHOWECBS) + ahb_print_active_ecb(); + + /***************************************\ + * Unlink it from the queue * + \***************************************/ + ahb_remove_timeout(ecb); + + /***************************************\ + * If it's immediate, don't try abort it * + \***************************************/ + if(ecb->flags & ECB_IMMED) + { + ecb->xs->retries = 0; /* I MEAN IT ! */ + ecb->flags |= ECB_IMMED_FAIL; + ahb_done(unit,ecb,FAIL); + continue; + } + /***************************************\ + * If it has been through before, then * + * a previous abort has failed, don't * + * try abort again * + \***************************************/ + if(ecb->flags == ECB_ABORTED) /* abort timed out */ + { + printf("AGAIN"); + ecb->xs->retries = 0; /* I MEAN IT ! */ + ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST; + ahb_done(unit,ecb,FAIL); + } + else /* abort the operation that has timed out */ + { + printf("\n"); + ahb_send_mbox(unit,OP_ABORT_ECB,ecb->xs->targ,ecb); + /* 2 secs for the abort */ + ahb_add_timeout(ecb,2000 + ONETICK); + ecb->flags = ECB_ABORTED; + } + } + else + /***********************************************\ + * It has not timed out, adjust and leave * + \***********************************************/ + { + ecb->delta -= ONETICK; + ahb_furtherest -= ONETICK; + break; + } + } + splx(s); + timeout(ahb_timeout,arg,SLEEPTIME); +} + +ahb_show_scsi_cmd(struct scsi_xfer *xs) +{ + u_char *b = (u_char *)xs->cmd; + int i = 0; + if(!(xs->flags & SCSI_RESET)) + { + printf("ahb%d:%d:%d-" + ,xs->adapter + ,xs->targ + ,xs->lu); + while(i < xs->cmdlen ) + { + if(i) printf(","); + printf("%x",b[i++]); + } + printf("-\n"); + } + else + { + printf("ahb%d:%d:%d-RESET-\n" + ,xs->adapter + ,xs->targ + ,xs->lu + ); + } +} +ahb_print_ecb(ecb) +struct ecb *ecb; +{ + printf("ecb:%x op:%x cmdlen:%d senlen:%d\n" + ,ecb + ,ecb->opcode + ,ecb->cdblen + ,ecb->senselen); + printf(" datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n" + ,ecb->datalen + ,ecb->ecb_status.ha_status + ,ecb->ecb_status.targ_status + ,ecb->delta + ,ecb->flags); + ahb_show_scsi_cmd(ecb->xs); +} + +ahb_print_active_ecb() +{ + struct ecb *ecb; + ecb = ahb_soonest; + + while(ecb) + { + ahb_print_ecb(ecb); + ecb = ecb->later; + } + printf("Furtherest = %d\n",ahb_furtherest); +} diff --git a/sys/i386/isa/bt742a.c b/sys/i386/isa/bt742a.c new file mode 100644 index 000000000000..dcdba5b54ea5 --- /dev/null +++ b/sys/i386/isa/bt742a.c @@ -0,0 +1,1537 @@ +/* + * Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + */ + +/* + * HISTORY + * $Log: bt742a.c,v $ + * Revision 1.7 1992/08/24 22:40:16 jason + * BIG_DMA ifdef for 512 dma segments instead of 128 segments + * + * Revision 1.6 1992/08/24 21:01:58 jason + * many changes and bugfixes for osf1 + * + * Revision 1.5 1992/07/31 01:22:03 julian + * support improved scsi.h layout + * + * Revision 1.4 1992/07/25 03:11:26 julian + * check each request fro sane flags. + * + * Revision 1.3 1992/07/24 00:52:45 julian + * improved timeout handling. + * added support for two arguments to the sd_done (or equiv) call so that + * they can pre-queue several arguments. + * slightly clean up error handling + * + * Revision 1.2 1992/07/17 22:03:54 julian + * upgraded the timeout code. + * added support for UIO-based i/o (as used for pmem operations) + * + * Revision 1.1 1992/05/27 00:51:12 balsup + * machkern/cor merge + * + */ + +/* + * bt742a BT-1542A SCSI driver + */ + +#include <sys/types.h> +#include <bt.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/user.h> + +#ifdef MACH /* EITHER CMU OR OSF */ +#include <i386/ipl.h> +#include <i386at/scsi.h> +#include <i386at/scsiconf.h> + +#ifdef OSF /* OSF ONLY */ +#include <sys/table.h> +#include <i386/handler.h> +#include <i386/dispatcher.h> +#include <i386/AT386/atbus.h> + +#else OSF /* CMU ONLY */ +#include <i386at/atbus.h> +#include <i386/pio.h> +#endif OSF +#endif MACH /* end of MACH specific */ + +#ifdef __386BSD__ /* 386BSD specific */ +#define isa_dev isa_device +#define dev_unit id_unit +#define dev_addr id_iobase + +#include <i386/isa/isa_device.h> +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> +#endif __386BSD__ + + +#ifdef __386BSD__ +#include "ddb.h" +#if NDDB > 0 +int Debugger(); +#else NDDB +#define Debugger() panic("should call debugger here (adaptec.c)") +#endif NDDB +#endif __386BSD__ + +#ifdef MACH +int Debugger(); +#endif MACH + +extern int delaycount; /* from clock setup code */ +typedef unsigned long int physaddr; + +/* + * I/O Port Interface + */ + +#define BT_BASE bt_base[unit] +#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */ +#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */ +#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */ + +/* + * BT_CTRL_STAT bits (write) + */ + +#define BT_HRST 0x80 /* Hardware reset */ +#define BT_SRST 0x40 /* Software reset */ +#define BT_IRST 0x20 /* Interrupt reset */ +#define BT_SCRST 0x10 /* SCSI bus reset */ + +/* + * BT_CTRL_STAT bits (read) + */ + +#define BT_STST 0x80 /* Self test in Progress */ +#define BT_DIAGF 0x40 /* Diagnostic Failure */ +#define BT_INIT 0x20 /* Mbx Init required */ +#define BT_IDLE 0x10 /* Host Adapter Idle */ +#define BT_CDF 0x08 /* cmd/data out port full */ +#define BT_DF 0x04 /* Data in port full */ +#define BT_INVDCMD 0x01 /* Invalid command */ + +/* + * BT_CMD_DATA bits (write) + */ + +#define BT_NOP 0x00 /* No operation */ +#define BT_MBX_INIT 0x01 /* Mbx initialization */ +#define BT_START_SCSI 0x02 /* start scsi command */ +#define BT_START_BIOS 0x03 /* start bios command */ +#define BT_INQUIRE 0x04 /* Adapter Inquiry */ +#define BT_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */ +#define BT_SEL_TIMEOUT_SET 0x06 /* set selection time-out */ +#define BT_BUS_ON_TIME_SET 0x07 /* set bus-on time */ +#define BT_BUS_OFF_TIME_SET 0x08 /* set bus-off time */ +#define BT_SPEED_SET 0x09 /* set transfer speed */ +#define BT_DEV_GET 0x0a /* return installed devices */ +#define BT_CONF_GET 0x0b /* return configuration data */ +#define BT_TARGET_EN 0x0c /* enable target mode */ +#define BT_SETUP_GET 0x0d /* return setup data */ +#define BT_WRITE_CH2 0x1a /* write channel 2 buffer */ +#define BT_READ_CH2 0x1b /* read channel 2 buffer */ +#define BT_WRITE_FIFO 0x1c /* write fifo buffer */ +#define BT_READ_FIFO 0x1d /* read fifo buffer */ +#define BT_ECHO 0x1e /* Echo command data */ +#define BT_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */ +#define BT_INQUIRE_EXTENDED 0x8D /* Adapter Setup Inquiry */ + +struct bt_cmd_buf { + u_char byte[16]; +}; + +/* + * BT_INTR_PORT bits (read) + */ + +#define BT_ANY_INTR 0x80 /* Any interrupt */ +#define BT_SCRD 0x08 /* SCSI reset detected */ +#define BT_HACC 0x04 /* Command complete */ +#define BT_MBOA 0x02 /* MBX out empty */ +#define BT_MBIF 0x01 /* MBX in full */ + +/* + * Mail box defs + */ + +#define BT_MBX_SIZE 16 /* mail box size */ + +struct bt_mbx +{ + struct bt_mbx_out { + physaddr ccb_addr; + unsigned char dummy[3]; + unsigned char cmd; + } mbo [BT_MBX_SIZE]; + struct bt_mbx_in{ + physaddr ccb_addr; + unsigned char btstat; + unsigned char sdstat; + unsigned char dummy; + unsigned char stat; + } mbi[BT_MBX_SIZE]; +}; + +/* + * mbo.cmd values + */ + +#define BT_MBO_FREE 0x0 /* MBO entry is free */ +#define BT_MBO_START 0x1 /* MBO activate entry */ +#define BT_MBO_ABORT 0x2 /* MBO abort entry */ + +#define BT_MBI_FREE 0x0 /* MBI entry is free */ +#define BT_MBI_OK 0x1 /* completed without error */ +#define BT_MBI_ABORT 0x2 /* aborted ccb */ +#define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ +#define BT_MBI_ERROR 0x4 /* Completed with error */ + +extern struct bt_mbx bt_mbx[]; + +#if defined(BIG_DMA) +/* #define BT_NSEG 8192 /* Number of scatter gather segments - to much vm */ +#define BT_NSEG 512 +#else +#define BT_NSEG 33 +#endif /* BIG_DMA */ +struct bt_scat_gath + { + unsigned long seg_len; + physaddr seg_addr; + }; + +struct bt_ccb { + unsigned char opcode; + unsigned char :3,data_in:1,data_out:1,:3; + unsigned char scsi_cmd_length; + unsigned char req_sense_length; + /*------------------------------------longword boundary */ + unsigned long data_length; + /*------------------------------------longword boundary */ + physaddr data_addr; + /*------------------------------------longword boundary */ + unsigned char dummy[2]; + unsigned char host_stat; + unsigned char target_stat; + /*------------------------------------longword boundary */ + unsigned char target; + unsigned char lun; + unsigned char scsi_cmd[12]; /* 12 bytes (bytes only)*/ + unsigned char dummy2[1]; + unsigned char link_id; + /*------------------------------------4 longword boundary */ + physaddr link_addr; + /*------------------------------------longword boundary */ + physaddr sense_ptr; + /*------------------------------------longword boundary */ + struct scsi_sense_data scsi_sense; + /*------------------------------------longword boundary */ + struct bt_scat_gath scat_gath[BT_NSEG]; + /*------------------------------------longword boundary */ + struct bt_ccb *next; + /*------------------------------------longword boundary */ + struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ + /*------------------------------------longword boundary */ + struct bt_mbx_out *mbx; /* pointer to mail box */ + /*------------------------------------longword boundary */ + long int delta; /* difference from previous*/ + struct bt_ccb *later,*sooner; + int flags; +#define CCB_FREE 0 +#define CCB_ACTIVE 1 +#define CCB_ABORTED 2 +}; + +struct bt_ccb *bt_soonest = (struct bt_ccb *)0; +struct bt_ccb *bt_latest = (struct bt_ccb *)0; +long int bt_furtherest = 0; /* longest time in the timeout queue */ +/* + * opcode fields + */ + +#define BT_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ +#define BT_TARGET_CCB 0x01 /* SCSI Target CCB */ +#define BT_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather*/ +#define BT_RESET_CCB 0x81 /* SCSI Bus reset */ + + +/* + * bt_ccb.host_stat values + */ + +#define BT_OK 0x00 /* cmd ok */ +#define BT_LINK_OK 0x0a /* Link cmd ok */ +#define BT_LINK_IT 0x0b /* Link cmd ok + int */ +#define BT_SEL_TIMEOUT 0x11 /* Selection time out */ +#define BT_OVER_UNDER 0x12 /* Data over/under run */ +#define BT_BUS_FREE 0x13 /* Bus dropped at unexpected time */ +#define BT_INV_BUS 0x14 /* Invalid bus phase/sequence */ +#define BT_BAD_MBO 0x15 /* Incorrect MBO cmd */ +#define BT_BAD_CCB 0x16 /* Incorrect ccb opcode */ +#define BT_BAD_LINK 0x17 /* Not same values of LUN for links */ +#define BT_INV_TARGET 0x18 /* Invalid target direction */ +#define BT_CCB_DUP 0x19 /* Duplicate CCB received */ +#define BT_INV_CCB 0x1a /* Invalid CCB or segment list */ +#define BT_ABORTED 42 /* pseudo value from driver */ + + + +struct bt_setup +{ + u_char sync_neg:1; + u_char parity:1; + u_char :6; + u_char speed; + u_char bus_on; + u_char bus_off; + u_char num_mbx; + u_char mbx[4]; + struct + { + u_char offset:4; + u_char period:3; + u_char valid:1; + }sync[8]; + u_char disc_sts; +}; + +struct bt_config +{ + u_char chan; + u_char intr; + u_char scsi_dev:3; + u_char :5; +}; + +#define INT9 0x01 +#define INT10 0x02 +#define INT11 0x04 +#define INT12 0x08 +#define INT14 0x20 +#define INT15 0x40 + +#define EISADMA 0x00 +#define CHAN0 0x01 +#define CHAN5 0x20 +#define CHAN6 0x40 +#define CHAN7 0x80 + + + + +#ifdef MACH +extern physaddr kvtophys(); +#define PHYSTOKV(x) phystokv(x) +#define KVTOPHYS(x) kvtophys(x) +#endif MACH + +#ifdef __386BSD__ +#define PHYSTOKV(x) (x | 0xFE000000) +#define KVTOPHYS(x) vtophys(x) +#endif __386BSD__ + + + +#define PAGESIZ 4096 +#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); } + + +u_char bt_scratch_buf[256]; +#ifdef MACH +caddr_t bt_base[NBT]; /* base port for each board */ +#else MACH +short bt_base[NBT]; /* base port for each board */ +#endif MACH +struct bt_mbx bt_mbx[NBT]; +struct bt_ccb *bt_ccb_free[NBT]; +struct bt_ccb bt_ccb[NBT][BT_MBX_SIZE]; +struct scsi_xfer bt_scsi_xfer[NBT]; +struct isa_dev *btinfo[NBT]; +struct bt_ccb *bt_get_ccb(); +int bt_int[NBT]; +int bt_dma[NBT]; +int bt_scsi_dev[NBT]; +int bt_initialized[NBT]; +#if defined(OSF) +int bt_attached[NBT]; +#endif /* defined(OSF) */ + +/***********debug values *************/ +#define BT_SHOWCCBS 0x01 +#define BT_SHOWINTS 0x02 +#define BT_SHOWCMDS 0x04 +#define BT_SHOWMISC 0x08 +int bt_debug = 0; + + +int btprobe(), btattach(); +int btintr(); + +#ifdef MACH +struct isa_driver btdriver = { btprobe, 0, btattach, "bt", 0, 0, 0}; +int (*btintrs[])() = {btintr, 0}; +#endif MACH + +#ifdef __386BSD__ +struct isa_driver btdriver = { btprobe, btattach, "bt"}; +#endif __386BSD__ + +static int btunit = 0; + +#define bt_abortmbx(mbx) \ + (mbx)->cmd = BT_MBO_ABORT; \ + outb(BT_CMD_DATA_PORT, BT_START_SCSI); +#define bt_startmbx(mbx) \ + (mbx)->cmd = BT_MBO_START; \ + outb(BT_CMD_DATA_PORT, BT_START_SCSI); + + + +int bt_scsi_cmd(); +int bt_timeout(); +void btminphys(); +long int bt_adapter_info(); + +struct scsi_switch bt_switch = +{ + bt_scsi_cmd, + btminphys, + 0, + 0, + bt_adapter_info, + 0,0,0 +}; +#define BT_CMD_TIMEOUT_FUDGE 200 /* multiplied to get Secs */ +#define BT_RESET_TIMEOUT 1000000 +#define BT_SCSI_TIMEOUT_FUDGE 20 /* divided by for mSecs */ + + +/***********************************************************************\ +* bt_cmd(unit,icnt, ocnt,wait, retval, opcode, args) * +* Activate Adapter command * +* icnt: number of args (outbound bytes written after opcode) * +* ocnt: number of expected returned bytes * +* wait: number of seconds to wait for response * +* retval: buffer where to place returned bytes * +* opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ... * +* args: parameters * +* * +* Performs an adapter command through the ports. Not to be confused * +* with a scsi command, which is read in via the dma * +* One of the adapter commands tells it to read in a scsi command * +\***********************************************************************/ +bt_cmd(unit,icnt, ocnt, wait,retval, opcode, args) + +u_char *retval; +unsigned opcode; +u_char args; +{ + unsigned *ic = &opcode; + u_char oc; + register i; + int sts; + + /*******************************************************\ + * multiply the wait argument by a big constant * + * zero defaults to 1 * + \*******************************************************/ + if(!wait) + wait = BT_CMD_TIMEOUT_FUDGE * delaycount; + else + wait *= BT_CMD_TIMEOUT_FUDGE * delaycount; + /*******************************************************\ + * Wait for the adapter to go idle, unless it's one of * + * the commands which don't need this * + \*******************************************************/ + if (opcode != BT_MBX_INIT && opcode != BT_START_SCSI) + { + i = BT_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec?*/ + while (--i) + { + sts = inb(BT_CTRL_STAT_PORT); + if (sts & BT_IDLE) + { + break; + } + } + if (!i) + { + printf("bt_cmd: bt742a host not idle(0x%x)\n",sts); + return(ENXIO); + } + } + /*******************************************************\ + * Now that it is idle, if we expect output, preflush the* + * queue feeding to us. * + \*******************************************************/ + if (ocnt) + { + while((inb(BT_CTRL_STAT_PORT)) & BT_DF) + inb(BT_CMD_DATA_PORT); + } + + /*******************************************************\ + * Output the command and the number of arguments given * + * for each byte, first check the port is empty. * + \*******************************************************/ + icnt++; /* include the command */ + while (icnt--) + { + sts = inb(BT_CTRL_STAT_PORT); + for (i=0; i< wait; i++) + { + sts = inb(BT_CTRL_STAT_PORT); + if (!(sts & BT_CDF)) + break; + } + if (i >= wait) + { + printf("bt_cmd: bt742a cmd/data port full\n"); + outb(BT_CTRL_STAT_PORT, BT_SRST); + return(ENXIO); + } + outb(BT_CMD_DATA_PORT, (u_char)(*ic++)); + } + /*******************************************************\ + * If we expect input, loop that many times, each time, * + * looking for the data register to have valid data * + \*******************************************************/ + while (ocnt--) + { + sts = inb(BT_CTRL_STAT_PORT); + for (i=0; i< wait; i++) + { + sts = inb(BT_CTRL_STAT_PORT); + if (sts & BT_DF) + break; + } + if (i >= wait) + { + printf("bt_cmd: bt742a cmd/data port empty %d\n",ocnt); + return(ENXIO); + } + oc = inb(BT_CMD_DATA_PORT); + if (retval) + *retval++ = oc; + } + /*******************************************************\ + * Wait for the board to report a finised instruction * + \*******************************************************/ + i=BT_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */ + while (--i) + { + sts = inb(BT_INTR_PORT); + if (sts & BT_HACC) + { + break; + } + } + if (!i) + { + printf("bt_cmd: bt742a host not finished(0x%x)\n",sts); + return(ENXIO); + } + outb(BT_CTRL_STAT_PORT, BT_IRST); + return(0); +} + +/*******************************************************\ +* Check if the device can be found at the port given * +* and if so, set it up ready for further work * +* as an argument, takes the isa_dev structure from * +* autoconf.c * +\*******************************************************/ + +btprobe(dev) +struct isa_dev *dev; +{ + /***********************************************\ + * find unit and check we have that many defined * + \***********************************************/ + int unit = btunit; +#if defined(OSF) + static ihandler_t bt_handler[NBT]; + static ihandler_id_t *bt_handler_id[NBT]; + register ihandler_t *chp = &bt_handler[unit];; +#endif /* defined(OSF) */ + + dev->dev_unit = unit; + bt_base[unit] = dev->dev_addr; + if(unit >= NBT) + { + printf("bt: unit number (%d) too high\n",unit); + return(0); + } + /***********************************************\ + * Try initialise a unit at this location * + * sets up dma and bus speed, loads bt_int[unit]* + \***********************************************/ + if (bt_init(unit) != 0) + { + return(0); + } + + /***********************************************\ + * If it's there, put in it's interrupt vectors * + \***********************************************/ +#ifdef MACH +#if defined(OSF) /* OSF */ + chp->ih_level = dev->dev_pic; + chp->ih_handler = dev->dev_intr[0]; + chp->ih_resolver = i386_resolver; + chp->ih_rdev = dev; + chp->ih_stats.intr_type = INTR_DEVICE; + chp->ih_stats.intr_cnt = 0; + chp->ih_hparam[0].intparam = unit; + if ((bt_handler_id[unit] = handler_add(chp)) != NULL) + handler_enable(bt_handler_id[unit]); + else + panic("Unable to add bt interrupt handler"); +#else /* CMU */ + dev->dev_pic = bt_int[unit]; + take_dev_irq(dev); +#endif /* !defined(OSF) */ + printf("port=%x spl=%d\n", dev->dev_addr, dev->dev_spl); +#endif MACH +#ifdef __386BSD__ /* 386BSD */ + dev->id_irq = (1 << bt_int[unit]); + dev->id_drq = bt_dma[unit]; + printf("\n **"); +#endif __386BSD__ + + btunit++; + return(1); +} + +/***********************************************\ +* Attach all the sub-devices we can find * +\***********************************************/ +btattach(dev) +struct isa_dev *dev; +{ + int unit = dev->dev_unit; + + +#ifdef __386BSD__ + printf(" probing for scsi devices**\n"); +#endif __386BSD__ + + /***********************************************\ + * ask the adapter what subunits are present * + \***********************************************/ + scsi_attachdevs( unit, bt_scsi_dev[unit], &bt_switch); +#if defined(OSF) + bt_attached[unit]=1; +#endif /* defined(OSF) */ + if(!unit) /* only one for all boards */ + { + bt_timeout(0); + } +#ifdef __386BSD__ + printf("bt%d",unit); +#endif __386BSD__ + return; +} + +/***********************************************\ +* Return some information to the caller about * +* the adapter and it's capabilities * +\***********************************************/ +long int bt_adapter_info(unit) +int unit; +{ + return(2); /* 2 outstanding requests at a time per device */ +} + +/***********************************************\ +* Catch an interrupt from the adaptor * +\***********************************************/ +btintr(unit) +{ + struct bt_ccb *ccb; + unsigned char stat; + register i; + + if(scsi_debug & PRINTROUTINES) + printf("btintr "); + /***********************************************\ + * First acknowlege the interrupt, Then if it's * + * not telling about a completed operation * + * just return. * + \***********************************************/ + stat = inb(BT_INTR_PORT); + outb(BT_CTRL_STAT_PORT, BT_IRST); + if(scsi_debug & TRACEINTERRUPTS) + printf("int = 0x%x ",stat); + if (! (stat & BT_MBIF)) + return 1; + if(scsi_debug & TRACEINTERRUPTS) + printf("mbxi "); +#if defined(OSF) + if (!bt_attached[unit]) + { + return(1); + } +#endif /* defined(OSF) */ + /***********************************************\ + * If it IS then process the competed operation * + \***********************************************/ + for (i = 0; i < BT_MBX_SIZE; i++) + { + if (bt_mbx[unit].mbi[i].stat != BT_MBI_FREE) + { + ccb = (struct bt_ccb *)PHYSTOKV( + (bt_mbx[unit].mbi[i].ccb_addr)); + if((bt_debug & BT_SHOWCCBS) && ccb) + printf("<int ccb(%x)>",ccb); + if((stat = bt_mbx[unit].mbi[i].stat) != BT_MBI_OK) + { + switch(stat) + { + case BT_MBI_ABORT: + if(bt_debug & BT_SHOWMISC) + printf("abort "); + ccb->host_stat = BT_ABORTED; + break; + + case BT_MBI_UNKNOWN: + ccb = (struct bt_ccb *)0; + if(bt_debug & BT_SHOWMISC) + printf("unknown ccb for abort"); + break; + + case BT_MBI_ERROR: + break; + + default: + panic("Impossible mbxi status"); + + } + if((bt_debug & BT_SHOWCMDS ) && ccb) + { + u_char *cp; + cp = ccb->scsi_cmd; + printf("op=%x %x %x %x %x %x\n", + cp[0], cp[1], cp[2], + cp[3], cp[4], cp[5]); + printf("stat %x for mbi[%d]\n" + , bt_mbx[unit].mbi[i].stat, i); + printf("addr = 0x%x\n", ccb); + } + } + if(ccb) + { + bt_remove_timeout(ccb); + bt_done(unit,ccb); + } + bt_mbx[unit].mbi[i].stat = BT_MBI_FREE; + } + } + return(1); +} + +/***********************************************\ +* A ccb (and hence a mbx-out is put onto the * +* free list. * +\***********************************************/ +bt_free_ccb(unit,ccb, flags) +struct bt_ccb *ccb; +{ + unsigned int opri; + + if(scsi_debug & PRINTROUTINES) + printf("ccb%d(0x%x)> ",unit,flags); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + + ccb->next = bt_ccb_free[unit]; + bt_ccb_free[unit] = ccb; + ccb->flags = CCB_FREE; + /***********************************************\ + * If there were none, wake abybody waiting for * + * one to come free, starting with queued entries* + \***********************************************/ + if (!ccb->next) { + wakeup(&bt_ccb_free[unit]); + } + if (!(flags & SCSI_NOMASK)) + splx(opri); +} + +/***********************************************\ +* Get a free ccb (and hence mbox-out entry) * +\***********************************************/ +struct bt_ccb * +bt_get_ccb(unit,flags) +{ + unsigned opri; + struct bt_ccb *rc; + + if(scsi_debug & PRINTROUTINES) + printf("<ccb%d(0x%x) ",unit,flags); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + /***********************************************\ + * If we can and have to, sleep waiting for one * + * to come free * + \***********************************************/ + while ((!(rc = bt_ccb_free[unit])) && (!(flags & SCSI_NOSLEEP))) + { + sleep(&bt_ccb_free[unit], PRIBIO); + } + if (rc) + { + bt_ccb_free[unit] = rc->next; + rc->flags = CCB_ACTIVE; + } + if (!(flags & SCSI_NOMASK)) + splx(opri); + return(rc); +} + + +/***********************************************\ +* We have a ccb which has been processed by the * +* adaptor, now we look to see how the operation * +* went. Wake up the owner if waiting * +\***********************************************/ +bt_done(unit,ccb) +struct bt_ccb *ccb; +{ + struct scsi_sense_data *s1,*s2; + struct scsi_xfer *xs = ccb->xfer; + + if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) + printf("bt_done "); + /***********************************************\ + * Otherwise, put the results of the operation * + * into the xfer and call whoever started it * + \***********************************************/ + if ( ( ccb->host_stat != BT_OK + || ccb->target_stat != SCSI_OK) + && (!(xs->flags & SCSI_ERR_OK))) + { + + s1 = &(ccb->scsi_sense); + s2 = &(xs->sense); + + if(ccb->host_stat) + { + switch(ccb->host_stat) + { + case BT_ABORTED: /* No response */ + case BT_SEL_TIMEOUT: /* No response */ + if (bt_debug & BT_SHOWMISC) + { + printf("timeout reported back\n"); + } + xs->error = XS_TIMEOUT; + break; + default: /* Other scsi protocol messes */ + xs->error = XS_DRIVER_STUFFUP; + if (bt_debug & BT_SHOWMISC) + { + printf("unexpected host_stat: %x\n", + ccb->host_stat); + } + } + + } + else + { + switch(ccb->target_stat) + { + case 0x02: + /* structure copy!!!!!*/ + *s2=*s1; + xs->error = XS_SENSE; + break; + case 0x08: + xs->error = XS_BUSY; + break; + default: + if (bt_debug & BT_SHOWMISC) + { + printf("unexpected target_stat: %x\n", + ccb->target_stat); + } + xs->error = XS_DRIVER_STUFFUP; + } + } + } + else /* All went correctly OR errors expected */ + { + xs->resid = 0; + } + xs->flags |= ITSDONE; + bt_free_ccb(unit,ccb, xs->flags); + if(xs->when_done) + (*(xs->when_done))(xs->done_arg,xs->done_arg2); +} + +/***********************************************\ +* Start the board, ready for normal operation * +\***********************************************/ +bt_init(unit) +int unit; +{ + unsigned char ad[4]; + volatile int i,sts; + struct bt_config conf; + + /***********************************************\ + * reset board, If it doesn't respond, assume * + * that it's not there.. good for the probe * + \***********************************************/ + + outb(BT_CTRL_STAT_PORT, BT_HRST|BT_SRST); + + for (i=0; i < BT_RESET_TIMEOUT; i++) + { + sts = inb(BT_CTRL_STAT_PORT) ; + if ( sts == (BT_IDLE | BT_INIT)) + break; + } + if (i >= BT_RESET_TIMEOUT) + { + if (bt_debug & BT_SHOWMISC) + printf("bt_init: No answer from bt742a board\n"); + return(ENXIO); + } + + /***********************************************\ + * Assume we have a board at this stage * + * setup dma channel from jumpers and save int * + * level * + \***********************************************/ +#ifdef __386BSD__ + printf("bt%d reading board settings, ",unit); +#define PRNT(x) +#else __386BSD__ + printf("bt%d:",unit); +#define PRNT(x) printf(x) +#endif __386BSD__ + + bt_cmd(unit,0, sizeof(conf), 0 ,&conf, BT_CONF_GET); + switch(conf.chan) + { + case EISADMA: + bt_dma[unit] = -1; + PRNT("eisa dma "); + break; + case CHAN0: + outb(0x0b, 0x0c); + outb(0x0a, 0x00); + bt_dma[unit] = 0; + PRNT("dma=0 "); + break; + case CHAN5: + outb(0xd6, 0xc1); + outb(0xd4, 0x01); + bt_dma[unit] = 5; + PRNT("dma=5 "); + break; + case CHAN6: + outb(0xd6, 0xc2); + outb(0xd4, 0x02); + bt_dma[unit] = 6; + PRNT("dma=6 "); + break; + case CHAN7: + outb(0xd6, 0xc3); + outb(0xd4, 0x03); + bt_dma[unit] = 7; + PRNT("dma=7 "); + break; + default: + printf("illegal dma setting %x\n",conf.chan); + return(EIO); + } + switch(conf.intr) + { + case INT9: + bt_int[unit] = 9; + PRNT("int=9 "); + break; + case INT10: + bt_int[unit] = 10; + PRNT("int=10 "); + break; + case INT11: + bt_int[unit] = 11; + PRNT("int=11 "); + break; + case INT12: + bt_int[unit] = 12; + PRNT("int=12 "); + break; + case INT14: + bt_int[unit] = 14; + PRNT("int=14 "); + break; + case INT15: + bt_int[unit] = 15; + PRNT("int=15 "); + break; + default: + printf("illegal int setting\n"); + return(EIO); + } + /* who are we on the scsi bus */ + bt_scsi_dev[unit] = conf.scsi_dev; + /***********************************************\ + * Initialize mail box * + \***********************************************/ + + *((physaddr *)ad) = KVTOPHYS(&bt_mbx[unit]); + bt_cmd(unit,5, 0, 0, 0, BT_MBX_INIT_EXTENDED + , BT_MBX_SIZE + , ad[0] + , ad[1] + , ad[2] + , ad[3]); + + /***********************************************\ + * link the ccb's with the mbox-out entries and * + * into a free-list * + \***********************************************/ + for (i=0; i < BT_MBX_SIZE; i++) { + bt_ccb[unit][i].next = bt_ccb_free[unit]; + bt_ccb_free[unit] = &bt_ccb[unit][i]; + bt_ccb_free[unit]->flags = CCB_FREE; + bt_ccb_free[unit]->mbx = &bt_mbx[unit].mbo[i]; + bt_mbx[unit].mbo[i].ccb_addr = KVTOPHYS(bt_ccb_free[unit]) ; + } + + /***********************************************\ + * Note that we are going and return (to probe) * + \***********************************************/ + bt_initialized[unit]++; + return( 0 ); +} + + +#ifndef min +#define min(x,y) (x < y ? x : y) +#endif min + + +void btminphys(bp) +struct buf *bp; +{ +#ifdef MACH +#if !defined(OSF) + bp->b_flags |= B_NPAGES; /* can support scat/gather */ +#endif /* defined(OSF) */ +#endif MACH + if(bp->b_bcount > ((BT_NSEG-1) * PAGESIZ)) + { + bp->b_bcount = ((BT_NSEG-1) * PAGESIZ); + } +} + +/***********************************************\ +* start a scsi operation given the command and * +* the data address. Also needs the unit, target * +* and lu * +\***********************************************/ +int bt_scsi_cmd(xs) +struct scsi_xfer *xs; +{ + struct scsi_sense_data *s1,*s2; + struct bt_ccb *ccb; + struct bt_scat_gath *sg; + int seg; /* scatter gather seg being worked on */ + int i = 0; + int rc = 0; + int thiskv; + physaddr thisphys,nextphys; + int unit =xs->adapter; + int bytes_this_seg,bytes_this_page,datalen,flags; + struct iovec *iovp; + + if(scsi_debug & PRINTROUTINES) + printf("bt_scsi_cmd "); + /***********************************************\ + * get a ccb (mbox-out) to use. If the transfer * + * is from a buf (possibly from interrupt time) * + * then we can't allow it to sleep * + \***********************************************/ + flags = xs->flags; + if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ + if(flags & ITSDONE) + { + printf("Already done?"); + xs->flags &= ~ITSDONE; + } + if(!(flags & INUSE)) + { + printf("Not in use?"); + xs->flags |= INUSE; + } + if (!(ccb = bt_get_ccb(unit,flags))) + { + xs->error = XS_DRIVER_STUFFUP; + return(TRY_AGAIN_LATER); + } + + if(bt_debug & BT_SHOWCCBS) + printf("<start ccb(%x)>",ccb); + if (ccb->mbx->cmd != BT_MBO_FREE) + printf("MBO not free\n"); + + /***********************************************\ + * Put all the arguments for the xfer in the ccb * + \***********************************************/ + ccb->xfer = xs; + if(flags & SCSI_RESET) + { + ccb->opcode = BT_RESET_CCB; + } + else + { + /* can't use S/G if zero length */ + ccb->opcode = (xs->datalen? + BT_INIT_SCAT_GATH_CCB + :BT_INITIATOR_CCB); + } + ccb->target = xs->targ;; + ccb->data_out = 0; + ccb->data_in = 0; + ccb->lun = xs->lu; + ccb->scsi_cmd_length = xs->cmdlen; + ccb->sense_ptr = KVTOPHYS(&(ccb->scsi_sense)); + ccb->req_sense_length = sizeof(ccb->scsi_sense); + + if((xs->datalen) && (!(flags & SCSI_RESET))) + { /* can use S/G only if not zero length */ + ccb->data_addr = KVTOPHYS(ccb->scat_gath); + sg = ccb->scat_gath ; + seg = 0; + if(flags & SCSI_DATA_UIO) + { + iovp = ((struct uio *)xs->data)->uio_iov; + datalen = ((struct uio *)xs->data)->uio_iovcnt; + xs->datalen = 0; + while ((datalen) && (seg < BT_NSEG)) + { + sg->seg_addr = (physaddr)iovp->iov_base; + xs->datalen += sg->seg_len = iovp->iov_len; + if(scsi_debug & SHOWSCATGATH) + printf("(0x%x@0x%x)" + ,iovp->iov_len + ,iovp->iov_base); + sg++; + iovp++; + seg++; + datalen--; + } + } + else + { + /***********************************************\ + * Set up the scatter gather block * + \***********************************************/ + + if(scsi_debug & SHOWSCATGATH) + printf("%d @0x%x:- ",xs->datalen,xs->data); + datalen = xs->datalen; + thiskv = (int)xs->data; + thisphys = KVTOPHYS(thiskv); + + while ((datalen) && (seg < BT_NSEG)) + { + bytes_this_seg = 0; + + /* put in the base address */ + sg->seg_addr = thisphys; + + if(scsi_debug & SHOWSCATGATH) + printf("0x%x",thisphys); + + /* do it at least once */ + nextphys = thisphys; + while ((datalen) && (thisphys == nextphys)) + /*********************************************\ + * This page is contiguous (physically) with * + * the the last, just extend the length * + \*********************************************/ + { + /* how far to the end of the page */ + nextphys= (thisphys & (~(PAGESIZ - 1))) + + PAGESIZ; + bytes_this_page = nextphys - thisphys; + /**** or the data ****/ + bytes_this_page = min(bytes_this_page + ,datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; + + /* get more ready for the next page */ + thiskv = (thiskv & (~(PAGESIZ - 1))) + + PAGESIZ; + if(datalen) + thisphys = KVTOPHYS(thiskv); + } + /********************************************\ + * next page isn't contiguous, finish the seg * + \********************************************/ + if(scsi_debug & SHOWSCATGATH) + printf("(0x%x)",bytes_this_seg); + sg->seg_len = bytes_this_seg; + sg++; + seg++; + } + } /*end of iov/kv decision */ + ccb->data_length = seg * sizeof(struct bt_scat_gath); + if(scsi_debug & SHOWSCATGATH) + printf("\n"); + if (datalen) + { /* there's still data, must have run out of segs! */ + printf("bt_scsi_cmd%d: more than %d DMA segs\n", + unit,BT_NSEG); + xs->error = XS_DRIVER_STUFFUP; + bt_free_ccb(unit,ccb,flags); + return(HAD_ERROR); + } + + } + else + { /* No data xfer, use non S/G values */ + ccb->data_addr = (physaddr)0; + ccb->data_length = 0; + } + ccb->link_id = 0; + ccb->link_addr = (physaddr)0; + /***********************************************\ + * Put the scsi command in the ccb and start it * + \***********************************************/ + if(!(flags & SCSI_RESET)) + { + bcopy(xs->cmd, ccb->scsi_cmd, ccb->scsi_cmd_length); + } + if(scsi_debug & SHOWCOMMANDS) + { + u_char *b = ccb->scsi_cmd; + if(!(flags & SCSI_RESET)) + { + int i = 0; + printf("bt%d:%d:%d-" + ,unit + ,ccb->target + ,ccb->lun); + while(i < ccb->scsi_cmd_length ) + { + if(i) printf(","); + printf("%x",b[i++]); + } + printf("-\n"); + } + else + { + printf("bt%d:%d:%d-RESET- " + ,unit + ,ccb->target + ,ccb->lun + ); + } + } + bt_startmbx(ccb->mbx); + /***********************************************\ + * Usually return SUCCESSFULLY QUEUED * + \***********************************************/ + if(scsi_debug & TRACEINTERRUPTS) + printf("cmd_sent "); + if (!(flags & SCSI_NOMASK)) + { + bt_add_timeout(ccb,xs->timeout); + return(SUCCESSFULLY_QUEUED); + } + /***********************************************\ + * If we can't use interrupts, poll on completion* + \***********************************************/ + { + int done = 0; + int count = delaycount * xs->timeout / BT_SCSI_TIMEOUT_FUDGE; + if(scsi_debug & TRACEINTERRUPTS) + printf("wait "); + while((!done) && count) + { + i=0; + while ( (!done) && i<BT_MBX_SIZE) + { + if ((bt_mbx[unit].mbi[i].stat != BT_MBI_FREE ) + && (PHYSTOKV(bt_mbx[unit].mbi[i].ccb_addr) + == (int)ccb)) + { + bt_mbx[unit].mbi[i].stat = BT_MBI_FREE; + bt_done(unit,ccb); + done++; + } + i++; + } + count--; + } + if (!count) + { + if (!(xs->flags & SCSI_SILENT)) + printf("cmd fail\n"); + bt_abortmbx(ccb->mbx); + count = delaycount * 2000 / BT_SCSI_TIMEOUT_FUDGE; + while((!done) && count) + { + i=0; + while ( (!done) && i<BT_MBX_SIZE) + { + if ((bt_mbx[unit].mbi[i].stat != BT_MBI_FREE ) + && (PHYSTOKV((bt_mbx[unit].mbi[i].ccb_addr) + == (int)ccb))) + { + bt_mbx[unit].mbi[i].stat = BT_MBI_FREE; + bt_done(unit,ccb); + done++; + } + i++; + } + count--; + } + if(!count) + { + printf("abort failed in wait\n"); + ccb->mbx->cmd = BT_MBO_FREE; + } + bt_free_ccb(unit,ccb,flags); + btintr(unit); + xs->error = XS_DRIVER_STUFFUP; + return(HAD_ERROR); + } + btintr(unit); + if(xs->error) return(HAD_ERROR); + return(COMPLETE); + } +} + +/* + * +----------+ +----------+ +----------+ + * bt_soonest--->| later |---->| later|---->| later|--->0 + * | [Delta] | | [Delta] | | [Delta] | + * 0<-----|sooner |<----|sooner |<----|sooner |<----bt_latest + * +----------+ +----------+ +----------+ + * + * bt_furtherest = sum(Delta[1..n]) + */ +bt_add_timeout(ccb,time) +struct bt_ccb *ccb; +int time; +{ + int timeprev; + struct bt_ccb *prev; + int s = splbio(); + + if(prev = bt_latest) /* yes, an assign */ + { + timeprev = bt_furtherest; + } + else + { + timeprev = 0; + } + while(prev && (timeprev > time)) + { + timeprev -= prev->delta; + prev = prev->sooner; + } + if(prev) + { + ccb->delta = time - timeprev; + if( ccb->later = prev->later) /* yes an assign */ + { + ccb->later->sooner = ccb; + ccb->later->delta -= ccb->delta; + } + else + { + bt_furtherest = time; + bt_latest = ccb; + } + ccb->sooner = prev; + prev->later = ccb; + } + else + { + if( ccb->later = bt_soonest) /* yes, an assign*/ + { + ccb->later->sooner = ccb; + ccb->later->delta -= time; + } + else + { + bt_furtherest = time; + bt_latest = ccb; + } + ccb->delta = time; + ccb->sooner = (struct bt_ccb *)0; + bt_soonest = ccb; + } + splx(s); +} + +bt_remove_timeout(ccb) +struct bt_ccb *ccb; +{ + int s = splbio(); + + if(ccb->sooner) + { + ccb->sooner->later = ccb->later; + } + else + { + bt_soonest = ccb->later; + } + if(ccb->later) + { + ccb->later->sooner = ccb->sooner; + ccb->later->delta += ccb->delta; + } + else + { + bt_latest = ccb->sooner; + bt_furtherest -= ccb->delta; + } + ccb->sooner = ccb->later = (struct bt_ccb *)0; + splx(s); +} + + +extern int hz; +#define ONETICK 500 /* milliseconds */ +#define SLEEPTIME ((hz * 1000) / ONETICK) +bt_timeout(arg) +int arg; +{ + struct bt_ccb *ccb; + int unit; + int s = splbio(); + + while( ccb = bt_soonest ) + { + if(ccb->delta <= ONETICK) + /***********************************************\ + * It has timed out, we need to do some work * + \***********************************************/ + { + unit = ccb->xfer->adapter; + printf("bt%d:%d device timed out\n",unit + ,ccb->xfer->targ); + if(bt_debug & BT_SHOWCCBS) + tfs_print_active_ccbs(); + + /***************************************\ + * Unlink it from the queue * + \***************************************/ + bt_remove_timeout(ccb); + + /***************************************\ + * If The ccb's mbx is not free, then * + * the board has gone south * + \***************************************/ + if(ccb->mbx->cmd != BT_MBO_FREE) + { + printf("bt%d not taking commands!\n" + ,unit); + Debugger(); + } + /***************************************\ + * If it has been through before, then * + * a previous abort has failed, don't * + * try abort again * + \***************************************/ + if(ccb->flags == CCB_ABORTED) /* abort timed out */ + { + printf("AGAIN"); + ccb->xfer->retries = 0; /* I MEAN IT ! */ + ccb->host_stat = BT_ABORTED; + bt_done(unit,ccb); + } + else /* abort the operation that has timed out */ + { + printf("\n"); + bt_abortmbx(ccb->mbx); + /* 2 secs for the abort */ + bt_add_timeout(ccb,2000 + ONETICK); + ccb->flags = CCB_ABORTED; + } + } + else + /***********************************************\ + * It has not timed out, adjust and leave * + \***********************************************/ + { + ccb->delta -= ONETICK; + bt_furtherest -= ONETICK; + break; + } + } + splx(s); + timeout(bt_timeout,arg,SLEEPTIME); +} + +tfs_print_ccb(ccb) +struct bt_ccb *ccb; +{ + printf("ccb:%x op:%x cmdlen:%d senlen:%d\n" + ,ccb + ,ccb->opcode + ,ccb->scsi_cmd_length + ,ccb->req_sense_length); + printf(" datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n" + ,ccb->data_length + ,ccb->host_stat + ,ccb->target_stat + ,ccb->delta + ,ccb->flags); +} + +tfs_print_active_ccbs() +{ + struct bt_ccb *ccb; + ccb = bt_soonest; + + while(ccb) + { + tfs_print_ccb(ccb); + ccb = ccb->later; + } + printf("Furtherest = %d\n",bt_furtherest); +} diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c new file mode 100644 index 000000000000..0fb77012d090 --- /dev/null +++ b/sys/i386/isa/clock.c @@ -0,0 +1,271 @@ +/*- + * 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. + * + * @(#)clock.c 7.2 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 5 00158 + * -------------------- ----- ---------------------- + * + * 14 Aug 92 Arne Henrik Juul Added code in the kernel to + * allow for DST in the BIOS. + * 17 Jan 93 Bruce Evans Fixed leap year and second + * calculations + * 01 Feb 93 Julian Elischer Added code to for the cpu + * speed independent spinwait() + * function, (used by scsi and others) + * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1 + * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock + * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait + * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I + * still kept the other fixes... Had to + * add back in findcpuspeed that Bruce + * had removed. + */ + +/* + * Primitive clock interrupt routines. + */ +#include "param.h" +#include "systm.h" +#include "time.h" +#include "kernel.h" +#include "machine/segments.h" +#include "i386/isa/icu.h" +#include "i386/isa/isa.h" +#include "i386/isa/rtc.h" +#include "i386/isa/timerreg.h" + +#define DAYST 119 +#define DAYEN 303 + +/* X-tals being what they are, it's nice to be able to fudge this one... */ +/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */ +#ifndef TIMER_FREQ +#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */ +#endif + +startrtclock() { + int s; + + findcpuspeed(); /* use the clock (while it's free) + to find the cpu speed */ + /* initialize 8253 clock */ + outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); + + /* Correct rounding will buy us a better precision in timekeeping */ + outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz); + outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256); + + /* initialize brain-dead battery powered clock */ + outb (IO_RTC, RTC_STATUSA); + outb (IO_RTC+1, 0x26); + outb (IO_RTC, RTC_STATUSB); + outb (IO_RTC+1, 2); + + outb (IO_RTC, RTC_DIAG); + if (s = inb (IO_RTC+1)) + printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); + outb (IO_RTC, RTC_DIAG); + outb (IO_RTC+1, 0); +} + +unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ + +#define FIRST_GUESS 0x2000 +findcpuspeed() +{ + unsigned char low; + unsigned int remainder; + + /* Put counter in count down mode */ + outb(IO_TIMER1+3, 0x34); + outb(IO_TIMER1, 0xff); + outb(IO_TIMER1, 0xff); + delaycount = FIRST_GUESS; + spinwait(1); + /* Read the value left in the counter */ + low = inb(IO_TIMER1); /* least siginifcant */ + remainder = inb(IO_TIMER1); /* most significant */ + remainder = (remainder<<8) + low ; + /* Formula for delaycount is : + * (loopcount * timer clock speed)/ (counter ticks * 1000) + */ + delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder); +} + + +/* convert 2 digit BCD number */ +bcd(i) +int i; +{ + return ((i/16)*10 + (i%16)); +} + +/* convert years to seconds (from 1970) */ +unsigned long +ytos(y) +int y; +{ + int i; + unsigned long ret; + + ret = 0; + for(i = 1970; i < y; i++) { + if (i % 4) ret += 365*24*60*60; + else ret += 366*24*60*60; + } + return ret; +} + +/* convert months to seconds */ +unsigned long +mtos(m,leap) +int m,leap; +{ + int i; + unsigned long ret; + + ret = 0; + for(i=1;i<m;i++) { + switch(i){ + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + ret += 31*24*60*60; break; + case 4: case 6: case 9: case 11: + ret += 30*24*60*60; break; + case 2: + if (leap) ret += 29*24*60*60; + else ret += 28*24*60*60; + } + } + return ret; +} + + +/* + * Initialize the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +inittodr(base) + time_t base; +{ + unsigned long sec; + int leap,day_week,t,yd; + int sa,s; + + /* do we have a realtime clock present? (otherwise we loop below) */ + sa = rtcin(RTC_STATUSA); + if (sa == 0xff || sa == 0) return; + + /* ready for a read? */ + while ((sa&RTCSA_TUP) == RTCSA_TUP) + sa = rtcin(RTC_STATUSA); + + sec = bcd(rtcin(RTC_YEAR)) + 1900; + if (sec < 1970) + sec += 100; + leap = !(sec % 4); sec = ytos(sec); /* year */ + yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */ + t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */ + day_week = rtcin(RTC_WDAY); /* day */ + sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */ + sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */ + sec += bcd(rtcin(RTC_SEC)); /* seconds */ + + /* XXX off by one? Need to calculate DST on SUNDAY */ + /* Perhaps we should have the RTC hold GMT time to save */ + /* us the bother of converting. */ + yd = yd / (24*60*60); + if ((yd >= DAYST) && ( yd <= DAYEN)) { + sec -= 60*60; + } + sec += tz.tz_minuteswest * 60; + + time.tv_sec = sec; +} + +#ifdef garbage +/* + * Initialze the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +test_inittodr(base) + time_t base; +{ + + outb(IO_RTC,9); /* year */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,8); /* month */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,7); /* day */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,4); /* hour */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,2); /* minutes */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,0); /* seconds */ + printf("%d\n",bcd(inb(IO_RTC+1))); + + time.tv_sec = base; +} +#endif + +/* + * Restart the clock. + */ +resettodr() +{ +} + +/* + * Wire clock interrupt in. + */ +#define V(s) __CONCAT(V, s) +extern V(clk)(); +enablertclock() { + setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); + INTREN(IRQ0); +} + +/* + * Delay for some number of milliseconds. + */ +void +spinwait(millisecs) + int millisecs; +{ + DELAY(1000 * millisecs); +} diff --git a/sys/i386/isa/fd.c b/sys/i386/isa/fd.c new file mode 100644 index 000000000000..a461e8153dff --- /dev/null +++ b/sys/i386/isa/fd.c @@ -0,0 +1,903 @@ +/*#define DEBUG 1*/ +/*- + * 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 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00153 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Julian Elischer Heavily re worked, see notes below + * + * Largely rewritten to handle multiple controllers and drives + * By Julian Elischer, Sun Apr 4 16:34:33 WST 1993 + */ +char rev[] = "$Revision: 1.10 $"; +/* + * $Header: /usr/src/sys.386bsd/i386/isa/RCS/fd.c,v 1.10 93/04/13 16:53:29 root Exp $ + */ +/* + * $Log: fd.c,v $ + * Revision 1.10 93/04/13 16:53:29 root + * make sure turning off a drive motor doesn't deselect another + * drive active at the time. + * Also added a pointer from the fd_data to it's fd_type. + * + * Revision 1.9 93/04/13 15:31:02 root + * make all seeks go through DOSEEK state so are sure of being done right. + * + * Revision 1.8 93/04/12 21:20:13 root + * only check if old fd is the one we are working on if there IS + * an old fd pointer. (in fdstate()) + * + * Revision 1.7 93/04/11 17:05:35 root + * cleanup timeouts etc. + * also fix bug to select teh correct drive when running > 1 drive + * at a time. + * + * Revision 1.6 93/04/05 00:48:45 root + * change a timeout and add version to banner message + * + * Revision 1.5 93/04/04 16:39:08 root + * first working version.. some floppy controllers don't seem to + * like 2 int. status inquiries in a row. + * + */ + +#include "fd.h" +#if NFD > 0 + +#include "param.h" +#include "dkbad.h" +#include "systm.h" +#include "conf.h" +#include "file.h" +#include "ioctl.h" +#include "buf.h" +#include "uio.h" +#include "i386/isa/isa.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/fdreg.h" +#include "i386/isa/icu.h" +#include "i386/isa/rtc.h" +#undef NFD +#define NFD 2 + +#define FDUNIT(s) ((s>>3)&1) +#define FDTYPE(s) ((s)&7) + +#define b_cylin b_resid +#define FDBLK 512 +#define NUMTYPES 4 + +struct fd_type { + int sectrac; /* sectors per track */ + int secsize; /* size code for sectors */ + int datalen; /* data len when secsize = 0 */ + int gap; /* gap len between sectors */ + int tracks; /* total num of tracks */ + int size; /* size of disk in sectors */ + int steptrac; /* steps per cylinder */ + int trans; /* transfer speed code */ + int heads; /* number of heads */ +}; + +struct fd_type fd_types[NUMTYPES] = +{ + { 18,2,0xFF,0x1B,80,2880,1,0,2 }, /* 1.44 meg HD 3.5in floppy */ + { 15,2,0xFF,0x1B,80,2400,1,0,2 }, /* 1.2 meg HD floppy */ + { 9,2,0xFF,0x23,40,720,2,1,2 }, /* 360k floppy in 1.2meg drive */ + { 9,2,0xFF,0x2A,40,720,1,1,2 }, /* 360k floppy in DD drive */ +}; + +#define DRVS_PER_CTLR 2 +/***********************************************************************\ +* Per controller structure. * +\***********************************************************************/ +struct fdc_data +{ + int fdcu; /* our unit number */ + int baseport; + int dmachan; + int flags; +#define FDC_ATTACHED 0x01 + struct fd_data *fd; + int fdu; /* the active drive */ + struct buf head; /* Head of buf chain */ + struct buf rhead; /* Raw head of buf chain */ + int state; + int retry; + int status[7]; /* copy of the registers */ +}fdc_data[(NFD+1)/DRVS_PER_CTLR]; + +/***********************************************************************\ +* Per drive structure. * +* N per controller (presently 2) (DRVS_PER_CTLR) * +\***********************************************************************/ +struct fd_data { + struct fdc_data *fdc; + int fdu; /* this unit number */ + int fdsu; /* this units number on this controller */ + int type; /* Drive type (HD, DD */ + struct fd_type *ft; /* pointer to the type descriptor */ + int flags; +#define FD_OPEN 0x01 /* it's open */ +#define FD_ACTIVE 0x02 /* it's active */ +#define FD_MOTOR 0x04 /* motor should be on */ +#define FD_MOTOR_WAIT 0x08 /* motor coming up */ + int skip; + int hddrv; + int track; /* where we think the head is */ +} fd_data[NFD]; + +/***********************************************************************\ +* Throughout this file the following conventions will be used: * +* fd is a pointer to the fd_data struct for the drive in question * +* fdc is a pointer to the fdc_data struct for the controller * +* fdu is the floppy drive unit number * +* fdcu is the floppy controller unit number * +* fdsu is the floppy drive unit number on that controller. (sub-unit) * +\***********************************************************************/ +typedef int fdu_t; +typedef int fdcu_t; +typedef int fdsu_t; +typedef struct fd_data *fd_p; +typedef struct fdc_data *fdc_p; + +#define DEVIDLE 0 +#define FINDWORK 1 +#define DOSEEK 2 +#define SEEKCOMPLETE 3 +#define IOCOMPLETE 4 +#define RECALCOMPLETE 5 +#define STARTRECAL 6 +#define RESETCTLR 7 +#define SEEKWAIT 8 +#define RECALWAIT 9 +#define MOTORWAIT 10 +#define IOTIMEDOUT 11 + +#ifdef DEBUG +char *fdstates[] = +{ +"DEVIDLE", +"FINDWORK", +"DOSEEK", +"SEEKCOMPLETE", +"IOCOMPLETE", +"RECALCOMPLETE", +"STARTRECAL", +"RESETCTLR", +"SEEKWAIT", +"RECALWAIT", +"MOTORWAIT", +"IOTIMEDOUT" +}; + + +int fd_debug = 1; +#define TRACE0(arg) if(fd_debug) printf(arg) +#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2) +#else DEBUG +#define TRACE0(arg) +#define TRACE1(arg1,arg2) +#endif DEBUG + +extern int hz; +/* state needed for current transfer */ + +/****************************************************************************/ +/* autoconfiguration stuff */ +/****************************************************************************/ +int fdprobe(), fdattach(), fd_turnoff(); + +struct isa_driver fddriver = { + fdprobe, fdattach, "fd", +}; + +/* + * probe for existance of controller + */ +fdprobe(dev) +struct isa_device *dev; +{ + fdcu_t fdcu = dev->id_unit; + if(fdc_data[fdcu].flags & FDC_ATTACHED) + { + printf("fdc: same unit (%d) used multiple times\n",fdcu); + return 0; + } + + fdc_data[fdcu].baseport = dev->id_iobase; + + /* see if it can handle a command */ + if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0) + { + return(0); + } + out_fdc(fdcu,0xDF); + out_fdc(fdcu,2); + return (IO_FDCSIZE); +} + +/* + * wire controller into system, look for floppy units + */ +fdattach(dev) +struct isa_device *dev; +{ + unsigned fdt,st0, cyl; + int hdr; + fdu_t fdu; + fdcu_t fdcu = dev->id_unit; + fdc_p fdc = fdc_data + fdcu; + fd_p fd; + int fdsu; + + fdc->fdcu = fdcu; + fdc->flags |= FDC_ATTACHED; + fdc->dmachan = dev->id_drq; + fdc->state = DEVIDLE; + + fdt = rtcin(RTC_FDISKETTE); + hdr = 0; + + /* check for each floppy drive */ + for (fdu = (fdcu * DRVS_PER_CTLR),fdsu = 0; + ((fdu < NFD) && (fdsu < DRVS_PER_CTLR)); + fdu++,fdsu++) + { + /* is there a unit? */ + if ((fdt & 0xf0) == RTCFDT_NONE) + continue; + +#ifdef notyet + /* select it */ + fd_turnon1(fdu); + spinwait(1000); /* 1 sec */ + out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */ + out_fdc(fdcu,fdsu); + spinwait(1000); /* 1 sec */ + + /* anything responding */ + out_fdc(fdcu,NE7CMD_SENSEI); + st0 = in_fdc(fdcu); + cyl = in_fdc(fdcu); + if (st0 & 0xd0) + continue; + +#endif + fd_data[fdu].track = -2; + fd_data[fdu].fdc = fdc; + fd_data[fdu].fdsu = fdsu; + /* yes, announce it */ + if (!hdr) + printf(" drives "); + else + printf(", "); + printf("%d: ", fdu); + + + if ((fdt & 0xf0) == RTCFDT_12M) { + printf("1.2M"); + fd_data[fdu].type = 1; + fd_data[fdu].ft = fd_types + 1; + + } + if ((fdt & 0xf0) == RTCFDT_144M) { + printf("1.44M"); + fd_data[fdu].type = 0; + fd_data[fdu].ft = fd_types + 0; + } + + fdt <<= 4; + fd_turnoff(fdu); + hdr = 1; + } + + printf(" %s ",rev); + /* Set transfer to 500kbps */ + outb(fdc->baseport+fdctl,0); /*XXX*/ +} + +int +fdsize(dev) +dev_t dev; +{ + return(0); +} + +/****************************************************************************/ +/* fdstrategy */ +/****************************************************************************/ +fdstrategy(bp) + register struct buf *bp; /* IO operation to perform */ +{ + register struct buf *dp,*dp0,*dp1; + long nblocks,blknum; + int s; + fdcu_t fdcu; + fdu_t fdu; + fdc_p fdc; + fd_p fd; + + fdu = FDUNIT(minor(bp->b_dev)); + fd = &fd_data[fdu]; + fdc = fd->fdc; + fdcu = fdc->fdcu; + /*type = FDTYPE(minor(bp->b_dev));*/ + + if ((fdu >= NFD) || (bp->b_blkno < 0)) { + printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n", + fdu, bp->b_blkno, bp->b_bcount); + pg("fd:error in fdstrategy"); + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR; + goto bad; + } + /* + * Set up block calculations. + */ + blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK; + nblocks = fd->ft->size; + if (blknum + (bp->b_bcount / FDBLK) > nblocks) { + if (blknum == nblocks) { + bp->b_resid = bp->b_bcount; + } else { + bp->b_error = ENOSPC; + bp->b_flags |= B_ERROR; + } + goto bad; + } + bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads); + dp = &(fdc->head); + s = splbio(); + disksort(dp, bp); + untimeout(fd_turnoff,fdu); /* a good idea */ + fdstart(fdcu); + splx(s); + return; + +bad: + biodone(bp); +} + +/****************************************************************************/ +/* motor control stuff */ +/* remember to not deselect the drive we're working on */ +/****************************************************************************/ +set_motor(fdcu_t fdcu, fdu_t fdu, int reset) +{ + int m0,m1; + int selunit; + fd_p fd; + if(fd = fdc_data[fdcu].fd)/* yes an assign! */ + { + selunit = fd->fdsu; + } + else + { + selunit = 0; + } + m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR; + m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR; + outb(fdc_data[fdcu].baseport+fdout, + selunit + | (reset ? 0 : (FDO_FRST|FDO_FDMAEN)) + | (m0 ? FDO_MOEN0 : 0) + | (m1 ? FDO_MOEN1 : 0)); + TRACE1("[0x%x->fdout]",( + selunit + | (reset ? 0 : (FDO_FRST|FDO_FDMAEN)) + | (m0 ? FDO_MOEN0 : 0) + | (m1 ? FDO_MOEN1 : 0))); +} + +fd_turnoff(fdu_t fdu) +{ + fd_p fd = fd_data + fdu; + fd->flags &= ~FD_MOTOR; + set_motor(fd->fdc->fdcu,fd->fdsu,0); +} + +fd_motor_on(fdu_t fdu) +{ + fd_p fd = fd_data + fdu; + fd->flags &= ~FD_MOTOR_WAIT; + if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT)) + { + fd_pseudointr(fd->fdc->fdcu); + } +} + +fd_turnon(fdu_t fdu) +{ + fd_p fd = fd_data + fdu; + if(!(fd->flags & FD_MOTOR)) + { + fd_turnon1(fdu); + fd->flags |= FD_MOTOR_WAIT; + timeout(fd_motor_on,fdu,hz); /* in 1 sec its ok */ + } +} + +fd_turnon1(fdu_t fdu) +{ + fd_p fd = fd_data + fdu; + fd->flags |= FD_MOTOR; + set_motor(fd->fdc->fdcu,fd->fdsu,0); +} + +/****************************************************************************/ +/* fdc in/out */ +/****************************************************************************/ +int +in_fdc(fdcu_t fdcu) +{ + int baseport = fdc_data[fdcu].baseport; + int i, j = 100000; + while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM)) + != (NE7_DIO|NE7_RQM) && j-- > 0) + if (i == NE7_RQM) return -1; + if (j <= 0) + return(-1); +#ifdef DEBUG + i = inb(baseport+fddata); + TRACE1("[fddata->0x%x]",(unsigned char)i); + return(i); +#else + return inb(baseport+fddata); +#endif +} + +out_fdc(fdcu_t fdcu,int x) +{ + int baseport = fdc_data[fdcu].baseport; + int i = 100000; + + while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0); + while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0); + if (i <= 0) return (-1); + outb(baseport+fddata,x); + TRACE1("[0x%x->fddata]",x); + return (0); +} + +static fdopenf; +/****************************************************************************/ +/* fdopen/fdclose */ +/****************************************************************************/ +Fdopen(dev, flags) + dev_t dev; + int flags; +{ + fdu_t fdu = FDUNIT(minor(dev)); + /*int type = FDTYPE(minor(dev));*/ + int s; + + /* check bounds */ + if (fdu >= NFD) return(ENXIO); + /*if (type >= NUMTYPES) return(ENXIO);*/ + fd_data[fdu].flags |= FD_OPEN; + + return 0; +} + +fdclose(dev, flags) + dev_t dev; +{ + fdu_t fdu = FDUNIT(minor(dev)); + fd_data[fdu].flags &= ~FD_OPEN; + return(0); +} + + +/***************************************************************\ +* fdstart * +* We have just queued something.. if the controller is not busy * +* then simulate the case where it has just finished a command * +* So that it (the interrupt routine) looks on the queue for more* +* work to do and picks up what we just added. * +* If the controller is already busy, we need do nothing, as it * +* will pick up our work when the present work completes * +\***************************************************************/ +fdstart(fdcu_t fdcu) +{ + register struct buf *dp,*bp; + int s; + fdu_t fdu; + + s = splbio(); + if(fdc_data[fdcu].state == DEVIDLE) + { + fdintr(fdcu); + } + splx(s); +} + +fd_timeout(fdcu_t fdcu) +{ + fdu_t fdu = fdc_data[fdcu].fdu; + int st0, st3, cyl; + struct buf *dp,*bp; + + dp = &fdc_data[fdcu].head; + bp = dp->b_actf; + + out_fdc(fdcu,NE7CMD_SENSED); + out_fdc(fdcu,fd_data[fdu].hddrv); + st3 = in_fdc(fdcu); + + out_fdc(fdcu,NE7CMD_SENSEI); + st0 = in_fdc(fdcu); + cyl = in_fdc(fdcu); + printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n", + fdu, + st0, + NE7_ST0BITS, + cyl, + st3, + NE7_ST3BITS); + + if (bp) + { + retrier(fdcu); + fdc_data[fdcu].status[0] = 0xc0; + fdc_data[fdcu].state = IOTIMEDOUT; + if( fdc_data[fdcu].retry < 6) + fdc_data[fdcu].retry = 6; + } + else + { + fdc_data[fdcu].fd = (fd_p) 0; + fdc_data[fdcu].fdu = -1; + fdc_data[fdcu].state = DEVIDLE; + } + fd_pseudointr(fdcu); +} + +/* just ensure it has the right spl */ +fd_pseudointr(fdcu_t fdcu) +{ + int s; + s = splbio(); + fdintr(fdcu); + splx(s); +} + +/***********************************************************************\ +* fdintr * +* keep calling the state machine until it returns a 0 * +* ALWAYS called at SPLBIO * +\***********************************************************************/ +fdintr(fdcu_t fdcu) +{ + fdc_p fdc = fdc_data + fdcu; + while(fdstate(fdcu, fdc)); +} + +/***********************************************************************\ +* The controller state machine. * +* if it returns a non zero value, it should be called again immediatly * +\***********************************************************************/ +int fdstate(fdcu_t fdcu, fdc_p fdc) +{ + int read,head,trac,sec,i,s,sectrac,cyl,st0; + unsigned long blknum; + fdu_t fdu = fdc->fdu; + fd_p fd; + register struct buf *dp,*bp; + + dp = &(fdc->head); + bp = dp->b_actf; + if(!bp) + { + /***********************************************\ + * nothing left for this controller to do * + * Force into the IDLE state, * + \***********************************************/ + fdc->state = DEVIDLE; + if(fdc->fd) + { + printf("unexpected valid fd pointer (fdu = %d)\n" + ,fdc->fdu); + fdc->fd = (fd_p) 0; + fdc->fdu = -1; + } + TRACE1("[fdc%d IDLE]",fdcu); + return(0); + } + fdu = FDUNIT(minor(bp->b_dev)); + fd = fd_data + fdu; + if (fdc->fd && (fd != fdc->fd)) + { + printf("confused fd pointers\n"); + } + read = bp->b_flags & B_READ; + TRACE1("fd%d",fdu); + TRACE1("[%s]",fdstates[fdc->state]); + TRACE1("(0x%x)",fd->flags); + untimeout(fd_turnoff, fdu); + timeout(fd_turnoff,fdu,4 * hz); + switch (fdc->state) + { + case DEVIDLE: + case FINDWORK: /* we have found new work */ + fdc->retry = 0; + fd->skip = 0; + fdc->fd = fd; + fdc->fdu = fdu; + /*******************************************************\ + * If the next drive has a motor startup pending, then * + * it will start up in it's own good time * + \*******************************************************/ + if(fd->flags & FD_MOTOR_WAIT) + { + fdc->state = MOTORWAIT; + return(0); /* come back later */ + } + /*******************************************************\ + * Maybe if it's not starting, it SHOULD be starting * + \*******************************************************/ + if (!(fd->flags & FD_MOTOR)) + { + fdc->state = MOTORWAIT; + fd_turnon(fdu); + return(0); + } + else /* at least make sure we are selected */ + { + set_motor(fdcu,fd->fdsu,0); + } + fdc->state = DOSEEK; + break; + case DOSEEK: + if (bp->b_cylin == fd->track) + { + fdc->state = SEEKCOMPLETE; + break; + } + out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */ + out_fdc(fdcu,fd->fdsu); /* Drive number */ + out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac); + fd->track = -2; + fdc->state = SEEKWAIT; + return(0); /* will return later */ + case SEEKWAIT: + /* allow heads to settle */ + timeout(fd_pseudointr,fdcu,hz/50); + fdc->state = SEEKCOMPLETE; + return(0); /* will return later */ + break; + + case SEEKCOMPLETE : /* SEEK DONE, START DMA */ + /* Make sure seek really happened*/ + if(fd->track == -2) + { + int descyl = bp->b_cylin * fd->ft->steptrac; + out_fdc(fdcu,NE7CMD_SENSEI); + i = in_fdc(fdcu); + cyl = in_fdc(fdcu); + if (cyl != descyl) + { + printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", fdu, + descyl, cyl, i, NE7_ST0BITS); + return(retrier(fdcu)); + } + } + + fd->track = bp->b_cylin; + isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip, + FDBLK, fdc->dmachan); + blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK + + fd->skip/FDBLK; + sectrac = fd->ft->sectrac; + sec = blknum % (sectrac * fd->ft->heads); + head = sec / sectrac; + sec = sec % sectrac + 1; +/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu; + + if (read) + { + out_fdc(fdcu,NE7CMD_READ); /* READ */ + } + else + { + out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */ + } + out_fdc(fdcu,head << 2 | fdu); /* head & unit */ + out_fdc(fdcu,fd->track); /* track */ + out_fdc(fdcu,head); + out_fdc(fdcu,sec); /* sector XXX +1? */ + out_fdc(fdcu,fd->ft->secsize); /* sector size */ + out_fdc(fdcu,sectrac); /* sectors/track */ + out_fdc(fdcu,fd->ft->gap); /* gap size */ + out_fdc(fdcu,fd->ft->datalen); /* data length */ + fdc->state = IOCOMPLETE; + timeout(fd_timeout,fdcu,2 * hz); + return(0); /* will return later */ + case IOCOMPLETE: /* IO DONE, post-analyze */ + untimeout(fd_timeout,fdcu); + for(i=0;i<7;i++) + { + fdc->status[i] = in_fdc(fdcu); + } + case IOTIMEDOUT: /*XXX*/ + isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip, + FDBLK, fdc->dmachan); + if (fdc->status[0]&0xF8) + { + return(retrier(fdcu)); + } + /* All OK */ + fd->skip += FDBLK; + if (fd->skip < bp->b_bcount) + { + /* set up next transfer */ + blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK + + fd->skip/FDBLK; + bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads)); + fdc->state = DOSEEK; + } + else + { + /* ALL DONE */ + fd->skip = 0; + bp->b_resid = 0; + dp->b_actf = bp->av_forw; + biodone(bp); + fdc->fd = (fd_p) 0; + fdc->fdu = -1; + fdc->state = FINDWORK; + } + return(1); + case RESETCTLR: + /* Try a reset, keep motor on */ + set_motor(fdcu,fd->fdsu,1); + DELAY(100); + set_motor(fdcu,fd->fdsu,0); + outb(fdc->baseport+fdctl,fd->ft->trans); + TRACE1("[0x%x->fdctl]",fd->ft->trans); + fdc->retry++; + fdc->state = STARTRECAL; + break; + case STARTRECAL: + out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */ + out_fdc(fdcu,0xDF); + out_fdc(fdcu,2); + out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */ + out_fdc(fdcu,fdu); + fdc->state = RECALWAIT; + return(0); /* will return later */ + case RECALWAIT: + /* allow heads to settle */ + timeout(fd_pseudointr,fdcu,hz/30); + fdc->state = RECALCOMPLETE; + return(0); /* will return later */ + case RECALCOMPLETE: + out_fdc(fdcu,NE7CMD_SENSEI); + st0 = in_fdc(fdcu); + cyl = in_fdc(fdcu); + if (cyl != 0) + { + printf("fd%d: recal failed ST0 %b cyl %d\n", fdu, + st0, NE7_ST0BITS, cyl); + return(retrier(fdcu)); + } + fd->track = 0; + /* Seek (probably) necessary */ + fdc->state = DOSEEK; + return(1); /* will return immediatly */ + case MOTORWAIT: + if(fd->flags & FD_MOTOR_WAIT) + { + return(0); /* time's not up yet */ + } + fdc->state = DOSEEK; + return(1); /* will return immediatly */ + default: + printf("Unexpected FD int->"); + out_fdc(fdcu,NE7CMD_SENSEI); + st0 = in_fdc(fdcu); + cyl = in_fdc(fdcu); + printf("ST0 = %lx, PCN = %lx\n",i,sec); + out_fdc(fdcu,0x4A); + out_fdc(fdcu,fd->fdsu); + for(i=0;i<7;i++) { + fdc->status[i] = in_fdc(fdcu); + } + printf("intr status :%lx %lx %lx %lx %lx %lx %lx ", + fdc->status[0], + fdc->status[1], + fdc->status[2], + fdc->status[3], + fdc->status[4], + fdc->status[5], + fdc->status[6] ); + return(0); + } + return(1); /* Come back immediatly to new state */ +} + +retrier(fdcu_t fdcu) +{ + fdc_p fdc = fdc_data + fdcu; + register struct buf *dp,*bp; + + dp = &(fdc->head); + bp = dp->b_actf; + + switch(fdc->retry) + { + case 0: case 1: case 2: + fdc->state = SEEKCOMPLETE; + break; + case 3: case 4: case 5: + fdc->state = STARTRECAL; + break; + case 6: + fdc->state = RESETCTLR; + break; + case 7: + break; + default: + { + printf("fd%d: hard error (ST0 %b ", + fdc->fdu, fdc->status[0], NE7_ST0BITS); + printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS); + printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS); + printf(" ST3 %b ", fdc->status[3], NE7_ST3BITS); + printf("cyl %d hd %d sec %d)\n", + fdc->status[4], fdc->status[5], fdc->status[6]); + } + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + bp->b_resid = bp->b_bcount - fdc->fd->skip; + dp->b_actf = bp->av_forw; + fdc->fd->skip = 0; + biodone(bp); + fdc->state = FINDWORK; + fdc->fd = (fd_p) 0; + fdc->fdu = -1; + return(1); + } + fdc->retry++; + return(1); +} + +#endif + diff --git a/sys/i386/isa/fdreg.h b/sys/i386/isa/fdreg.h new file mode 100644 index 000000000000..948f566dfda8 --- /dev/null +++ b/sys/i386/isa/fdreg.h @@ -0,0 +1,72 @@ +/*- + * 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 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00153 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Julian Elischer Heavily re worked, see notes below + */ + +/* + * AT floppy controller registers and bitfields + */ + +/* uses NEC765 controller */ +#include "../i386/isa/ic/nec765.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_MOEN0 0x10 /* motor enable drive 0 */ +#define FDO_MOEN1 0x20 /* motor enable drive 1 */ +#define FDO_MOEN2 0x30 /* motor enable drive 2 */ +#define FDO_MOEN3 0x40 /* motor enable drive 3 */ + +#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 */ + + diff --git a/sys/i386/isa/ic/i8042.h b/sys/i386/isa/ic/i8042.h new file mode 100644 index 000000000000..4d04ce5b1d8e --- /dev/null +++ b/sys/i386/isa/ic/i8042.h @@ -0,0 +1,23 @@ +#define KBSTATP 0x64 /* kbd controller status port (I) */ +#define KBS_DIB 0x01 /* kbd data in buffer */ +#define KBS_IBF 0x02 /* kbd input buffer low */ +#define KBS_WARM 0x04 /* kbd input buffer low */ +#define KBS_OCMD 0x08 /* kbd output buffer has command */ +#define KBS_NOSEC 0x10 /* kbd security lock not engaged */ +#define KBS_TERR 0x20 /* kbd transmission error */ +#define KBS_RERR 0x40 /* kbd receive error */ +#define KBS_PERR 0x80 /* kbd parity error */ + +#define KBCMDP 0x64 /* kbd controller port (O) */ +#define KBDATAP 0x60 /* kbd data port (I) */ +#define KBOUTP 0x60 /* kbd data port (O) */ + +#define K_LDCMDBYTE 0x60 + +#define KC8_TRANS 0x40 /* convert to old scan codes */ +#define KC8_OLDPC 0x20 /* old 9bit codes instead of new 11bit */ +#define KC8_DISABLE 0x10 /* disable keyboard */ +#define KC8_IGNSEC 0x08 /* ignore security lock */ +#define KC8_CPU 0x04 /* exit from protected mode reset */ +#define KC8_IEN 0x01 /* enable interrupt */ +#define CMDBYTE (KC8_TRANS|KC8_IGNSEC|KC8_CPU|KC8_IEN) diff --git a/sys/i386/isa/ic/i8237.h b/sys/i386/isa/ic/i8237.h new file mode 100644 index 000000000000..dc269f2cfc2d --- /dev/null +++ b/sys/i386/isa/ic/i8237.h @@ -0,0 +1,9 @@ +/* + * Intel 8237 DMA Controller + */ + +#define DMA37MD_SINGLE 0x40 /* single pass mode */ +#define DMA37MD_CASCADE 0xc0 /* cascade mode */ +#define DMA37MD_WRITE 0x04 /* read the device, write memory operation */ +#define DMA37MD_READ 0x08 /* write the device, read memory operation */ + diff --git a/sys/i386/isa/ic/nec765.h b/sys/i386/isa/ic/nec765.h new file mode 100644 index 000000000000..b84b46e799cf --- /dev/null +++ b/sys/i386/isa/ic/nec765.h @@ -0,0 +1,71 @@ +/*- + * 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. + * + * @(#)nec765.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * Nec 765 floppy disc controller definitions + */ + +/* Main status register */ +#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */ +#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */ +#define NE7_CB 0x10 /* Diskette Controller Busy */ +#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */ +#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */ +#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */ + +/* Status register ST0 */ +#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head" + +/* Status register ST1 */ +#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am" + +/* Status register ST2 */ +#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam" + +/* Status register ST3 */ +#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002" + +/* Commands */ +#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit + parameters byte */ +#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */ +#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */ +#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */ +#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */ +#define NE7CMD_RECAL 7 /* recalibrate drive - requires + unit select byte */ +#define NE7CMD_SENSEI 8 /* sense controller interrupt status */ +#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte + and new cyl byte */ diff --git a/sys/i386/isa/ic/ns16450.h b/sys/i386/isa/ic/ns16450.h new file mode 100644 index 000000000000..f05903577662 --- /dev/null +++ b/sys/i386/isa/ic/ns16450.h @@ -0,0 +1,49 @@ +/*- + * 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. + * + * @(#)ns16450.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * NS16450 UART registers + */ + +#define com_data 0 /* data register (R/W) */ +#define com_dlbl 0 /* divisor latch low (W) */ +#define com_dlbh 1 /* divisor latch high (W) */ +#define com_ier 1 /* interrupt enable (W) */ +#define com_iir 2 /* interrupt identification (R) */ +#define com_lctl 3 /* line control register (R/W) */ +#define com_cfcr 3 /* line control register (R/W) */ +#define com_mcr 4 /* modem control register (R/W) */ +#define com_lsr 5 /* line status register (R/W) */ +#define com_msr 6 /* modem status register (R/W) */ diff --git a/sys/i386/isa/ic/ns16550.h b/sys/i386/isa/ic/ns16550.h new file mode 100644 index 000000000000..e20e9aa58a89 --- /dev/null +++ b/sys/i386/isa/ic/ns16550.h @@ -0,0 +1,50 @@ +/*- + * 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. + * + * @(#)ns16550.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * NS16550 UART registers + */ + +#define com_data 0 /* data register (R/W) */ +#define com_dlbl 0 /* divisor latch low (W) */ +#define com_dlbh 1 /* divisor latch high (W) */ +#define com_ier 1 /* interrupt enable (W) */ +#define com_iir 2 /* interrupt identification (R) */ +#define com_fifo 2 /* FIFO control (W) */ +#define com_lctl 3 /* line control register (R/W) */ +#define com_cfcr 3 /* line control register (R/W) */ +#define com_mcr 4 /* modem control register (R/W) */ +#define com_lsr 5 /* line status register (R/W) */ +#define com_msr 6 /* modem status register (R/W) */ diff --git a/sys/i386/isa/icu.h b/sys/i386/isa/icu.h new file mode 100644 index 000000000000..4866d8d0a822 --- /dev/null +++ b/sys/i386/isa/icu.h @@ -0,0 +1,109 @@ +/*- + * 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. + * + * @(#)icu.h 5.6 (Berkeley) 5/9/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00158 + * -------------------- ----- ---------------------- + * + * 25 Apr 93 Bruce Evans New fast interrupt code (intr-0.1) + */ + +/* + * AT/386 Interrupt Control constants + * W. Jolitz 8/89 + */ + +#ifndef __ICU__ +#define __ICU__ + +#ifndef LOCORE + +/* + * Interrupt "level" mechanism variables, masks, and macros + */ +extern unsigned imen; /* interrupt mask enable */ +extern unsigned cpl; /* current priority level mask */ + +extern unsigned highmask; /* group of interrupts masked with splhigh() */ +extern unsigned ttymask; /* group of interrupts masked with spltty() */ +extern unsigned biomask; /* group of interrupts masked with splbio() */ +extern unsigned netmask; /* group of interrupts masked with splimp() */ + +#define INTREN(s) (imen &= ~(s), SET_ICUS()) +#define INTRDIS(s) (imen |= (s), SET_ICUS()) +#define INTRMASK(msk,s) (msk |= (s)) +#if 0 +#define SET_ICUS() (outb(IO_ICU1 + 1, imen), outb(IU_ICU2 + 1, imen >> 8)) +#else +/* + * XXX - IO_ICU* are defined in isa.h, not icu.h, and nothing much bothers to + * include isa.h, while too many things include icu.h. + */ +#define SET_ICUS() (outb(0x21, imen), outb(0xa1, imen >> 8)) +#endif + +#endif + +/* + * Interrupt enable bits -- in order of priority + */ +#define IRQ0 0x0001 /* highest priority - timer */ +#define IRQ1 0x0002 +#define IRQ_SLAVE 0x0004 +#define IRQ8 0x0100 +#define IRQ9 0x0200 +#define IRQ2 IRQ9 +#define IRQ10 0x0400 +#define IRQ11 0x0800 +#define IRQ12 0x1000 +#define IRQ13 0x2000 +#define IRQ14 0x4000 +#define IRQ15 0x8000 +#define IRQ3 0x0008 +#define IRQ4 0x0010 +#define IRQ5 0x0020 +#define IRQ6 0x0040 +#define IRQ7 0x0080 /* lowest - parallel printer */ + +/* + * Interrupt Control offset into Interrupt descriptor table (IDT) + */ +#define ICU_OFFSET 32 /* 0-31 are processor exceptions */ +#define ICU_LEN 16 /* 32-47 are ISA interrupts */ + +#endif __ICU__ diff --git a/sys/i386/isa/icu.s b/sys/i386/isa/icu.s new file mode 100644 index 000000000000..1b93c65ae4a9 --- /dev/null +++ b/sys/i386/isa/icu.s @@ -0,0 +1,376 @@ +/*- + * Copyright (c) 1989, 1990 William F. Jolitz. + * 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. + * + * @(#)icu.s 7.2 (Berkeley) 5/21/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 5 00167 + * -------------------- ----- ---------------------- + * + * 28 Nov 92 Frank MacLachlan Aligned addresses and data + * on 32bit boundaries. + * 24 Mar 93 Rodney W. Grimes Added interrupt counters for vmstat + * also stray and false intr counters added + * 20 Apr 93 Bruce Evans New npx-0.5 code + * 25 Apr 93 Bruce Evans Support new interrupt code (intr-0.1) + * Rodney W. Grimes Reimplement above patches.. + * 17 May 93 Rodney W. Grimes Redid the interrupt counter stuff + * moved the counters to vectors.s so + * they are next to the name tables. + * 04 Jun 93 Bruce Evans Fixed irq_num vs id_num for multiple + * devices configed on the same irq with + * respect to ipending. Restructured + * not to use BUILD_VECTORS. + * Rodney W. Grimes softsio1 only works if you have sio + * serial driver, added #include sio.h + * and #ifdef NSIO > 0 to protect it. + */ + +/* + * AT/386 + * Vector interrupt control section + */ + +/* + * XXX - this file is now misnamed. All spls are now soft and the only thing + * related to the hardware icu is that the bit numbering is the same in the + * soft priority masks as in the hard ones. + */ + +#include "sio.h" +#define HIGHMASK 0xffff +#define SOFTCLOCKMASK 0x8000 + + .data + .globl _cpl +_cpl: .long 0xffff # current priority (all off) + .globl _imen +_imen: .long 0xffff # interrupt mask enable (all off) +# .globl _highmask +_highmask: .long HIGHMASK + .globl _ttymask +_ttymask: .long 0 + .globl _biomask +_biomask: .long 0 + .globl _netmask +_netmask: .long 0 + .globl _ipending +_ipending: .long 0 +vec: + .long vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7 + .long vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15 + +#define GENSPL(name, mask, event) \ + .globl _spl/**/name ; \ + ALIGN_TEXT ; \ +_spl/**/name: ; \ + COUNT_EVENT(_intrcnt_spl, event) ; \ + movl _cpl,%eax ; \ + movl %eax,%edx ; \ + orl mask,%edx ; \ + movl %edx,_cpl ; \ + SHOW_CPL ; \ + ret + +#define FASTSPL(mask) \ + movl mask,_cpl ; \ + SHOW_CPL + +#define FASTSPL_VARMASK(varmask) \ + movl varmask,%eax ; \ + movl %eax,_cpl ; \ + SHOW_CPL + + .text + + ALIGN_TEXT +unpend_v: + COUNT_EVENT(_intrcnt_spl, 0) + bsfl %eax,%eax # slow, but not worth optimizing + btrl %eax,_ipending + jnc unpend_v_next # some intr cleared the in-memory bit + SHOW_IPENDING + movl Vresume(,%eax,4),%eax + testl %eax,%eax + je noresume + jmp %eax + + ALIGN_TEXT +/* + * XXX - must be some fastintr, need to register those too. + */ +noresume: +#if NSIO > 0 + call _softsio1 +#endif +unpend_v_next: + movl _cpl,%eax + movl %eax,%edx + notl %eax + andl _ipending,%eax + je none_to_unpend + jmp unpend_v + +/* + * Handle return from interrupt after device handler finishes + */ + ALIGN_TEXT +doreti: + COUNT_EVENT(_intrcnt_spl, 1) + addl $4,%esp # discard unit arg + popl %eax # get previous priority +/* + * Now interrupt frame is a trap frame! + * + * XXX - setting up the interrupt frame to be almost a stack frame is mostly + * a waste of time. + */ + movl %eax,_cpl + SHOW_CPL + movl %eax,%edx + notl %eax + andl _ipending,%eax + jne unpend_v +none_to_unpend: + testl %edx,%edx # returning to zero priority? + jne 1f # nope, going to non-zero priority + movl _netisr,%eax + testl %eax,%eax # check for softint s/traps + jne 2f # there are some + jmp test_resched # XXX - schedule jumps better + COUNT_EVENT(_intrcnt_spl, 2) # XXX + + ALIGN_TEXT # XXX +1: # XXX + COUNT_EVENT(_intrcnt_spl, 3) + popl %es + popl %ds + popal + addl $8,%esp + iret + +#include "../net/netisr.h" + +#define DONET(s, c, event) ; \ + .globl c ; \ + btrl $s,_netisr ; \ + jnc 1f ; \ + COUNT_EVENT(_intrcnt_spl, event) ; \ + call c ; \ +1: + + ALIGN_TEXT +2: + COUNT_EVENT(_intrcnt_spl, 4) +/* + * XXX - might need extra locking while testing reg copy of netisr, but + * interrupt routines setting it would not cause any new problems (since we + * don't loop, fresh bits will not be processed until the next doreti or spl0). + */ + testl $~((1 << NETISR_SCLK) | (1 << NETISR_AST)),%eax + je test_ASTs # no net stuff, just temporary AST's + FASTSPL_VARMASK(_netmask) + DONET(NETISR_RAW, _rawintr, 5) +#ifdef INET + DONET(NETISR_IP, _ipintr, 6) +#endif +#ifdef IMP + DONET(NETISR_IMP, _impintr, 7) +#endif +#ifdef NS + DONET(NETISR_NS, _nsintr, 8) +#endif + FASTSPL($0) +test_ASTs: + btrl $NETISR_SCLK,_netisr + jnc test_resched + COUNT_EVENT(_intrcnt_spl, 9) + FASTSPL($SOFTCLOCKMASK) +/* + * Back to an interrupt frame for a moment. + */ + pushl $0 # previous cpl (probably not used) + pushl $0x7f # dummy unit number + call _softclock + addl $8,%esp # discard dummies + FASTSPL($0) +test_resched: +#ifdef notused1 + btrl $NETISR_AST,_netisr + jnc 2f +#endif +#ifdef notused2 + cmpl $0,_want_resched + je 2f +#endif + cmpl $0,_astpending # XXX - put it back in netisr to + je 2f # reduce the number of tests + testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp) + # to non-kernel (i.e., user)? + je 2f # nope, leave + COUNT_EVENT(_intrcnt_spl, 10) + movl $0,_astpending + call _trap +2: + COUNT_EVENT(_intrcnt_spl, 11) + popl %es + popl %ds + popal + addl $8,%esp + iret + +/* + * Interrupt priority mechanism + * -- soft splXX masks with group mechanism (cpl) + * -- h/w masks for currently active or unused interrupts (imen) + * -- ipending = active interrupts currently masked by cpl + */ + + GENSPL(bio, _biomask, 12) + GENSPL(clock, $HIGHMASK, 13) /* splclock == splhigh ex for count */ + GENSPL(high, $HIGHMASK, 14) + GENSPL(imp, _netmask, 15) /* splimp == splnet except for count */ + GENSPL(net, _netmask, 16) + GENSPL(softclock, $SOFTCLOCKMASK, 17) + GENSPL(tty, _ttymask, 18) + + .globl _splnone + .globl _spl0 + ALIGN_TEXT +_splnone: +_spl0: + COUNT_EVENT(_intrcnt_spl, 19) +in_spl0: + movl _cpl,%eax + pushl %eax # save old priority + testl $(1 << NETISR_RAW) | (1 << NETISR_IP),_netisr + je over_net_stuff_for_spl0 + movl _netmask,%eax # mask off those network devices + movl %eax,_cpl # set new priority + SHOW_CPL +/* + * XXX - what about other net intrs? + */ + DONET(NETISR_RAW, _rawintr, 20) +#ifdef INET + DONET(NETISR_IP, _ipintr, 21) +#endif +over_net_stuff_for_spl0: + movl $0,_cpl # set new priority + SHOW_CPL + movl _ipending,%eax + testl %eax,%eax + jne unpend_V + popl %eax # return old priority + ret + + .globl _splx + ALIGN_TEXT +_splx: + COUNT_EVENT(_intrcnt_spl, 22) + movl 4(%esp),%eax # new priority + testl %eax,%eax + je in_spl0 # going to "zero level" is special + COUNT_EVENT(_intrcnt_spl, 23) + movl _cpl,%edx # save old priority + movl %eax,_cpl # set new priority + SHOW_CPL + notl %eax + andl _ipending,%eax + jne unpend_V_result_edx + movl %edx,%eax # return old priority + ret + + ALIGN_TEXT +unpend_V_result_edx: + pushl %edx +unpend_V: + COUNT_EVENT(_intrcnt_spl, 24) + bsfl %eax,%eax + btrl %eax,_ipending + jnc unpend_V_next + SHOW_IPENDING + movl Vresume(,%eax,4),%edx + testl %edx,%edx + je noresumeV +/* + * We would prefer to call the intr handler directly here but that doesn't + * work for badly behaved handlers that want the interrupt frame. Also, + * there's a problem determining the unit number. We should change the + * interface so that the unit number is not determined at config time. + */ + jmp *vec(,%eax,4) + + ALIGN_TEXT +/* + * XXX - must be some fastintr, need to register those too. + */ +noresumeV: +#if NSIO > 0 + call _softsio1 +#endif +unpend_V_next: + movl _cpl,%eax + notl %eax + andl _ipending,%eax + jne unpend_V + popl %eax + ret + +#define BUILD_VEC(irq_num) \ + ALIGN_TEXT ; \ +vec/**/irq_num: ; \ + int $ICU_OFFSET + (irq_num) ; \ + popl %eax ; \ + ret + + BUILD_VEC(0) + BUILD_VEC(1) + BUILD_VEC(2) + BUILD_VEC(3) + BUILD_VEC(4) + BUILD_VEC(5) + BUILD_VEC(6) + BUILD_VEC(7) + BUILD_VEC(8) + BUILD_VEC(9) + BUILD_VEC(10) + BUILD_VEC(11) + BUILD_VEC(12) + BUILD_VEC(13) + BUILD_VEC(14) + BUILD_VEC(15) diff --git a/sys/i386/isa/if_is.c b/sys/i386/isa/if_is.c new file mode 100644 index 000000000000..df164d626018 --- /dev/null +++ b/sys/i386/isa/if_is.c @@ -0,0 +1,747 @@ +/*- + * Copyright (c) 1990, 1991 William F. Jolitz. + * Copyright (c) 1990 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. + * + * @(#)if_ne.c 7.4 (Berkeley) 5/21/91 + */ + +/* + * Isolink 4110-2 Ethernet driver + */ + +#include "is.h" +#if NIS > 0 + +#include "param.h" +#include "systm.h" +#include "mbuf.h" +#include "buf.h" +#include "protosw.h" +#include "socket.h" +#include "ioctl.h" +#include "errno.h" +#include "syslog.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 + +#ifdef NS +#include "netns/ns.h" +#include "netns/ns_if.h" +#endif + +#include "i386/isa/isa_device.h" +#include "i386/isa/if_isreg.h" +#include "i386/isa/icu.h" + +#include "vm/vm.h" + +/* Function prototypes */ +int isprobe(), isattach(); +int isioctl(),isinit(),isstart(); + +struct isa_driver isdriver = { + isprobe, isattach, "is", +}; + + +struct mbuf *isget(); + +#define ETHER_MIN_LEN 64 + +/* + * Ethernet software status per interface. + * + * Each interface is referenced by a network interface structure, + * ns_if, which the routing code uses to locate the interface. + * This structure contains the output queue for the interface, its address, ... + */ +struct is_softc { + struct arpcom ns_ac; /* Ethernet common part */ +#define ns_if ns_ac.ac_if /* network-visible interface */ +#define ns_addr ns_ac.ac_enaddr /* hardware Ethernet address */ + int last_rd; + int last_td; + int no_td; +} is_softc[NIS] ; + +struct init_block init_block; +struct mds *td, *rd; +unsigned char *rbuf,*tbuf; + +int isc; + +iswrcsr(port,val) + u_short port; + u_short val; +{ + outw(isc+RAP,port); + outw(isc+RDP,val); +} + +u_short isrdcsr(port) + u_short port; +{ + outw(isc+RAP,port); + return(inw(isc+RDP)); +} + +isprobe(dvp) + struct isa_device *dvp; +{ + int val,i,s; + register struct is_softc *ns = &is_softc[0]; + + isc = dvp->id_iobase; + s = splimp(); + + /* Stop the lance chip, put it known state */ + iswrcsr(0,STOP); + DELAY(100); + + /* is there a lance? */ + iswrcsr(3, 0xffff); + if (isrdcsr(3) != 7) { + isc = 0; + return (0); + } + iswrcsr(3, 0); + + /* Extract board address */ + for(i=0; i < 6; i++) ns->ns_addr[i] = inb(isc+(i*2)); + + splx(s); + return (1); +} + + + +/* + * Reset of interface. + */ +isreset(unit, uban) + int unit, uban; +{ + if (unit >= NIS) + return; + printf("is%d: reset\n", unit); + isinit(unit); +} + +/* + * Interface exists: make available by filling in network interface + * record. System will initialize the interface when it is ready + * to accept packets. We get the ethernet address here. + */ +isattach(dvp) + struct isa_device *dvp; +{ + int unit = dvp->id_unit; + register struct is_softc *is = &is_softc[unit]; + register struct ifnet *ifp = &is->ns_if; + + /* Set up DMA */ + isa_dmacascade(dvp->id_drq); + + ifp->if_unit = unit; + ifp->if_name = isdriver.name ; + ifp->if_mtu = ETHERMTU; + printf (" ethernet address %s", ether_sprintf(is->ns_addr)) ; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; + ifp->if_init = isinit; + ifp->if_output = ether_output; + ifp->if_start = isstart; + ifp->if_ioctl = isioctl; + ifp->if_reset = isreset; + ifp->if_watchdog = 0; + if_attach(ifp); +} + + +/* Lance initialisation block set up */ +init_mem() +{ + int i; + u_long temp; + + /* Allocate memory */ +/* Temporary hack, will use kmem_alloc in future */ +#define MAXMEM ((NRBUF+NTBUF)*(BUFSIZE) + (NRBUF+NTBUF)*sizeof(struct mds) + 8) +static u_char lance_mem[MAXMEM]; + + + /* Align message descriptors on quad word boundary + (this is essential) */ + + temp = (u_long) &lance_mem; + temp = (temp+8) - (temp%8); + rd = (struct mds *) temp; + td = (struct mds *) (temp + (NRBUF*sizeof(struct mds))); + temp += (NRBUF+NTBUF) * sizeof(struct mds); + + init_block.mode = 0; + + /* Get ethernet address */ + for (i=0; i<6; i++) + init_block.padr[i] = inb(isc+(i*2)); + + /* Clear multicast address for now */ + for (i=0; i<8; i++) + init_block.ladrf[i] = 0; + + init_block.rdra = kvtop(rd); + init_block.rlen = ((kvtop(rd) >> 16) & 0xff) | (RLEN<<13); + init_block.tdra = kvtop(td); + init_block.tlen = ((kvtop(td) >> 16) & 0xff) | (TLEN<<13); + + /* Set up receive ring descriptors */ + rbuf = (unsigned char *)temp; + for (i=0; i<NRBUF; i++) { + (rd+i)->addr = kvtop(temp); + (rd+i)->flags= ((kvtop(temp) >> 16) & 0xff) | OWN; + (rd+i)->bcnt = -BUFSIZE; + (rd+i)->mcnt = 0; + temp += BUFSIZE; + } + + /* Set up transmit ring descriptors */ + tbuf = (unsigned char *)temp; +#ifdef ISDEBUG + printf("rd = %x,td = %x, rbuf = %x, tbuf = %x,td+1=%x\n",rd,td,rbuf,tbuf,td+1); +#endif + for (i=0; i<NTBUF; i++) { + (td+i)->addr = kvtop(temp); + (td+i)->flags= ((kvtop(temp) >> 16) & 0xff); + (td+i)->bcnt = 0; + (td+i)->mcnt = 0; + temp += BUFSIZE; + } + +} + +/* + * Initialization of interface; set up initialization block + * and transmit/receive descriptor rings. + */ +isinit(unit) + int unit; +{ + register struct is_softc *ns = &is_softc[unit]; + struct ifnet *ifp = &ns->ns_if; + int s; + register i; + + if (ifp->if_addrlist == (struct ifaddr *)0) return; + + ns->last_rd = ns->last_td = ns->no_td = 0; + s = splimp(); + + /* Set up lance's memory area */ + init_mem(); + + /* Stop Lance to get access to other registers */ + iswrcsr(0,STOP); + + /* I wish I knew what this was */ + iswrcsr(3,0); + + /* Give lance the physical address of its memory area */ + iswrcsr(1,kvtop(&init_block)); + iswrcsr(2,(kvtop(&init_block) >> 16) & 0xff); + + /* OK, let's try and initialise the Lance */ + iswrcsr(0,INIT); + + /* Wait for initialisation to finish */ + for(i=0; i<1000; i++){ + if (isrdcsr(0)&IDON) + break; + } + if (isrdcsr(0)&IDON) { + /* Start lance */ + iswrcsr(0,STRT|IDON|INEA); + ns->ns_if.if_flags |= IFF_RUNNING; + isstart(ifp); + } + else + printf("Isolink card failed to initialise\n"); + + splx(s); +} + +/* + * Setup output on interface. + * Get another datagram to send off of the interface queue, + * and map it to the interface before starting the output. + * called only at splimp or interrupt level. + */ +isstart(ifp) + struct ifnet *ifp; +{ + register struct is_softc *ns = &is_softc[ifp->if_unit]; + struct mbuf *m0, *m; + unsigned char *buffer; + u_short len; + int i; + struct mds *cdm; + + + if ((ns->ns_if.if_flags & IFF_RUNNING) == 0) + return; + + do { + cdm = (td + ns->last_td); + if (cdm->flags&OWN) + return; + + IF_DEQUEUE(&ns->ns_if.if_snd, m); + + if (m == 0) + return; + + /* + * Copy the mbuf chain into the transmit buffer + */ + + buffer = tbuf+(BUFSIZE*ns->last_td); + len=0; + for (m0=m; m != 0; m=m->m_next) { + bcopy(mtod(m,caddr_t),buffer,m->m_len); + buffer += m->m_len; + len += m->m_len; + } + + m_freem(m0); + len = MAX(len,ETHER_MIN_LEN); + + /* + * Init transmit registers, and set transmit start flag. + */ + + cdm->flags |= (OWN|STP|ENP); + cdm->bcnt = -len; + cdm->mcnt = 0; +#ifdef ISDEBUG + xmit_print(ns->last_td); +#endif + + iswrcsr(0,TDMD|INEA); + if (++ns->last_td >= NTBUF) + ns->last_td=0; + }while(++ns->no_td < NTBUF); + ns->no_td = NTBUF; + ns->ns_if.if_flags |= IFF_OACTIVE; +#ifdef ISDEBUG + printf("no_td = %x, last_td = %x\n",ns->no_td, ns->last_td); +#endif + return(0); +} + + +/* + * Controller interrupt. + */ +isintr(unit) +{ + register struct is_softc *ns = &is_softc[unit]; + u_short isr; + + while((isr=isrdcsr(0))&INTR) { + if (isr&ERR) { + if (isr&BABL) + printf("BABL\n"); + if (isr&CERR) + printf("CERR\n"); + if (isr&MISS) + printf("MISS\n"); + if (isr&MERR) + printf("MERR\n"); + iswrcsr(0,BABL|CERR|MISS|MERR|INEA); + } + if (!(isr&TXON)) { + isreset(unit); + return(1); + } + if (!(isr&RXON)) { + isreset(unit); + return(1); + } + if (isr&RINT) { + isrint(unit); + } + if (isr&TINT) { + iswrcsr(0,TINT|INEA); + istint(unit); + } + } +} + +istint(unit) + int unit; +{ + struct is_softc *is = &is_softc[unit]; + register struct ifnet *ifp = &is->ns_if; + int i,loopcount=0; + struct mds *cdm; + + do { + if ((i=is->last_td - is->no_td) < 0) + i+=NTBUF; + cdm = (td+i); +#ifdef ISDEBUG + printf("Trans cdm = %x\n",cdm); +#endif + if (cdm->flags&OWN) { + if (loopcount) + break; + return; + } + loopcount++; + is->ns_if.if_flags &= ~IFF_OACTIVE; + }while(--is->no_td > 0); + isstart(ifp); + +} + +#define NEXTRDS \ + if (++rmd == NRBUF) rmd=0, cdm=rd; else ++cdm + +isrint(unit) + int unit; +{ + register struct is_softc *is=&is_softc[unit]; + register int rmd = is->last_rd; + struct mds *cdm = (rd + rmd); + + /* Out of sync with hardware, should never happen */ + + if (cdm->flags & OWN) { + printf("is0 error: out of sync\n"); + iswrcsr(0,RINT|INEA); + return; + } + + /* Process all buffers with valid data */ + while (!(cdm->flags&OWN)) { + /* Clear interrupt to avoid race condition */ + iswrcsr(0,RINT|INEA); + if (cdm->flags&ERR) { + if (cdm->flags&FRAM) + printf("FRAM\n"); + if (cdm->flags&OFLO) + printf("OFLO\n"); + if (cdm->flags&CRC) + printf("CRC\n"); + if (cdm->flags&RBUFF) + printf("RBUFF\n"); + }else + if (cdm->flags&(STP|ENP) != (STP|ENP)) { + do { + iswrcsr(0,RINT|INEA); + cdm->mcnt = 0; + cdm->flags |= OWN; + NEXTRDS; + }while (!(cdm->flags&(OWN|ERR|STP|ENP))); + is->last_rd = rmd; + printf("Chained buffer\n"); + if ((cdm->flags & (OWN|ERR|STP|ENP)) != ENP) { + isreset(unit); + return; + } + }else + { +#ifdef ISDEBUG + recv_print(is->last_rd); +#endif + isread(is,rbuf+(BUFSIZE*rmd),cdm->mcnt); + } + + cdm->flags |= OWN; + cdm->mcnt = 0; + NEXTRDS; +#ifdef ISDEBUG + printf("is->last_rd = %x, cdm = %x\n",is->last_rd,cdm); +#endif + } /* while */ + is->last_rd = rmd; +} /* isrint */ + +/* + * Pass a packet to the higher levels. + * We deal with the trailer protocol here. + */ +isread(ns, buf, len) + register struct is_softc *ns; + char *buf; + int len; +{ + register struct ether_header *eh; + struct mbuf *m; + int off, resid; + register struct ifqueue *inq; + + /* + * Deal with trailer protocol: if type is trailer type + * get true type from first 16-bit word past data. + * Remember that type was trailer by setting off. + */ + eh = (struct ether_header *)buf; + eh->ether_type = ntohs((u_short)eh->ether_type); + len = len - sizeof(struct ether_header) - 4; +#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) + if (eh->ether_type >= ETHERTYPE_TRAIL && + eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { + off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; + if (off >= ETHERMTU) return; /* sanity */ + eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *)); + resid = ntohs(*(nedataaddr(eh, off+2, u_short *))); + if (off + resid > len) return; /* sanity */ + len = off + resid; + } else off = 0; + + if (len == 0) return; + + /* + * Pull packet off interface. Off is nonzero if packet + * has trailing header; neget will then force this header + * information to be at the front, but we still have to drop + * the type and length which are at the front of any trailer data. + */ + m = isget(buf, len, off, &ns->ns_if); + if (m == 0) return; + + ether_input(&ns->ns_if, eh, m); +} + +/* + * Supporting routines + */ + +/* + * Pull read data off a interface. + * Len is length of data, with local net header stripped. + * Off is non-zero if a trailer protocol was used, and + * gives the offset of the trailer information. + * We copy the trailer information and then all the normal + * data into mbufs. When full cluster sized units are present + * we copy into clusters. + */ +struct mbuf * +isget(buf, totlen, off0, ifp) + caddr_t buf; + int totlen, off0; + struct ifnet *ifp; +{ + struct mbuf *top, **mp, *m, *p; + int off = off0, len; + register caddr_t cp = buf; + char *epkt; + + buf += sizeof(struct ether_header); + cp = buf; + epkt = cp + totlen; + + + if (off) { + cp += off + 2 * sizeof(u_short); + totlen -= 2 * sizeof(u_short); + } + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + return (0); + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = totlen; + m->m_len = MHLEN; + + top = 0; + mp = ⊤ + while (totlen > 0) { + if (top) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == 0) { + m_freem(top); + return (0); + } + m->m_len = MLEN; + } + len = min(totlen, 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; + totlen -= len; + if (cp == epkt) + cp = buf; + } + return (top); +} + +/* + * Process an ioctl request. + */ +isioctl(ifp, cmd, data) + register struct ifnet *ifp; + int cmd; + caddr_t data; +{ + register struct ifaddr *ifa = (struct ifaddr *)data; + struct is_softc *ns = &is_softc[ifp->if_unit]; + struct ifreq *ifr = (struct ifreq *)data; + int s = splimp(), error = 0; + + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + isinit(ifp->if_unit); /* before arpwhohas */ + ((struct arpcom *)ifp)->ac_ipaddr = + IA_SIN(ifa)->sin_addr; + arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); + break; +#endif +#ifdef NS + case AF_NS: + { + register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); + + if (ns_nullhost(*ina)) + ina->x_host = *(union ns_host *)(ns->ns_addr); + else { + /* + * The manual says we can't change the address + * while the receiver is armed, + * so reset everything + */ + ifp->if_flags &= ~IFF_RUNNING; + bcopy((caddr_t)ina->x_host.c_host, + (caddr_t)ns->ns_addr, sizeof(ns->ns_addr)); + } + isinit(ifp->if_unit); /* does ne_setaddr() */ + break; + } +#endif + default: + isinit(ifp->if_unit); + break; + } + break; + + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) == 0 && + ifp->if_flags & IFF_RUNNING) { + ifp->if_flags &= ~IFF_RUNNING; + iswrcsr(0,STOP); + } else if (ifp->if_flags & IFF_UP && + (ifp->if_flags & IFF_RUNNING) == 0) + isinit(ifp->if_unit); + break; + +#ifdef notdef + case SIOCGHWADDR: + bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data, + sizeof(ns->ns_addr)); + break; +#endif + + default: + error = EINVAL; + } + splx(s); + return (error); +} + +recv_print(no) + int no; +{ + struct mds *rmd; + int len,i; + + rmd = (rd+no); + len = rmd->mcnt; + printf("Receive buffer %d, len = %d\n",no,len); + printf("Status %x\n",isrdcsr(0)); + for (i=0; i<len; i++) + printf("%x ",*(rbuf+(BUFSIZE*no)+i)); + printf("\n"); +} + +xmit_print(no) + int no; +{ + struct mds *rmd; + int i; + u_short len; + + rmd = (td+no); + len = -(rmd->bcnt); + printf("Transmit buffer %d, len = %d\n",no,len); + printf("Status %x\n",isrdcsr(0)); + printf("addr %x, flags %x, bcnt %x, mcnt %x\n", + rmd->addr,rmd->flags,rmd->bcnt,rmd->mcnt); + for (i=0; i<len; i++) + printf("%x ",*(tbuf+(BUFSIZE*no)+i)); + printf("\n"); +} + +#endif diff --git a/sys/i386/isa/if_isreg.h b/sys/i386/isa/if_isreg.h new file mode 100644 index 000000000000..790313d6d9d4 --- /dev/null +++ b/sys/i386/isa/if_isreg.h @@ -0,0 +1,90 @@ +/* Declarations specific to this driver */ +#define NTBUF 2 +#define TLEN 1 +#define NRBUF 8 +#define RLEN 3 +#define BUFSIZE 1518 +#define RAP 0xe +#define RDP 0xc + +/* Control and status register 0 flags */ + +#define ERR 0x8000 +#define BABL 0x4000 +#define CERR 0x2000 +#define MISS 0x1000 +#define MERR 0x0800 +#define RINT 0x0400 +#define TINT 0x0200 +#define IDON 0x0100 +#define INTR 0x0080 +#define INEA 0x0040 +#define RXON 0x0020 +#define TXON 0x0010 +#define TDMD 0x0008 +#define STOP 0x0004 +#define STRT 0x0002 +#define INIT 0x0001 + +/* Coontrol and status register 3 flags */ + +#define BSWP 0x0004 +#define ACON 0x0002 +#define BCON 0x0001 + +/* Initialisation block (must be on word boundary) */ + +struct init_block { + u_short mode; /* Mode register */ + u_char padr[6]; /* Ethernet address */ + u_char ladrf[8]; /* Logical address filter (multicast) */ + u_short rdra; /* Low order pointer to receive ring */ + u_short rlen; /* High order pointer and no. rings */ + u_short tdra; /* Low order pointer to transmit ring */ + u_short tlen; /* High order pointer and no rings */ + }; + +/* Mode settings */ + +#define PROM 0x8000 /* Promiscuous */ +#define INTL 0x0040 /* Internal loopback */ +#define DRTY 0x0020 /* Disable retry */ +#define COLL 0x0010 /* Force collision */ +#define DTCR 0x0008 /* Disable transmit crc */ +#define LOOP 0x0004 /* Loop back */ +#define DTX 0x0002 /* Disable transmitter */ +#define DRX 0x0001 /* Disable receiver */ + +/* Message descriptor structure */ + +struct mds { + u_short addr; + u_short flags; + u_short bcnt; + u_short mcnt; + }; + +/* Receive ring status flags */ + +#define OWN 0x8000 /* Owner bit, 0=host, 1=Lance */ +#define MDERR 0x4000 /* Error */ +#define FRAM 0x2000 /* Framing error error */ +#define OFLO 0x1000 /* Silo overflow */ +#define CRC 0x0800 /* CRC error */ +#define RBUFF 0x0400 /* Buffer error */ +#define STP 0x0200 /* Start of packet */ +#define ENP 0x0100 /* End of packet */ + +/* Transmit ring flags */ + +#define MORE 0x1000 /* More than 1 retry */ +#define ONE 0x0800 /* One retry */ +#define DEF 0x0400 /* Deferred transmit */ + +/* Transmit errors */ + +#define TBUFF 0x8000 /* Buffer error */ +#define UFLO 0x4000 /* Silo underflow */ +#define LCOL 0x1000 /* Late collision */ +#define LCAR 0x0800 /* Loss of carrier */ +#define RTRY 0x0400 /* Tried 16 times */ diff --git a/sys/i386/isa/isa.c b/sys/i386/isa/isa.c new file mode 100644 index 000000000000..8707b43d4c68 --- /dev/null +++ b/sys/i386/isa/isa.c @@ -0,0 +1,766 @@ +/*- + * Copyright (c) 1991 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. + * + * @(#)isa.c 7.2 (Berkeley) 5/13/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 4 00163 + * -------------------- ----- ---------------------- + * + * 18 Aug 92 Frank Maclachlan *See comments below + * 25 Mar 93 Rodney W. Grimes Added counter for stray interrupt, + * turned on logging of stray interrupts, + * Now prints maddr, msize, and flags + * after finding a device. + * 26 Apr 93 Bruce Evans New intr-0.1 code + * Rodney W. Grimes Only print io address if id_alive != -1 + * 17 May 93 Rodney W. Grimes renamed stray interrupt counters to + * work with new intr-0.1 code. + * Enabled printf for interrupt masks to + * aid in bug reports. + * 27 May 93 Guido van Rooij New routine add find_isa_dev + */ +static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/isa/RCS/isa.c,v 1.2 92/01/21 14:34:23 william Exp Locker: root $"; + +/* + * code to manage AT bus + * + * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com): + * Fixed uninitialized variable problem and added code to deal + * with DMA page boundaries in isa_dmarangecheck(). Fixed word + * mode DMA count compution and reorganized DMA setup code in + * isa_dmastart() + */ + +#include "param.h" +#include "systm.h" +#include "conf.h" +#include "file.h" +#include "buf.h" +#include "uio.h" +#include "syslog.h" +#include "malloc.h" +#include "rlist.h" +#include "machine/segments.h" +#include "vm/vm.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/isa.h" +#include "i386/isa/icu.h" +#include "i386/isa/ic/i8237.h" +#include "i386/isa/ic/i8042.h" + +/* +** Register definitions for DMA controller 1 (channels 0..3): +*/ +#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */ +#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */ +#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */ +#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */ + +/* +** Register definitions for DMA controller 2 (channels 4..7): +*/ +#define DMA2_CHN(c) (IO_DMA1 + 2*(2*(c))) /* addr reg for channel c */ +#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */ +#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */ +#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */ + +int config_isadev __P((struct isa_device *, u_int *)); + +#ifdef notyet +struct rlist *isa_iomem; + +/* + * Configure all ISA devices + */ +isa_configure() { + struct isa_device *dvp; + struct isa_driver *dp; + + splhigh(); + INTREN(IRQ_SLAVE); + /*rlist_free(&isa_iomem, 0xa0000, 0xfffff);*/ + for (dvp = isa_devtab_tty; dvp; dvp++) + (void) config_isadev(dvp, &ttymask); + for (dvp = isa_devtab_bio; dvp; dvp++) + (void) config_isadev(dvp, &biomask); + for (dvp = isa_devtab_net; dvp; dvp++) + (void) config_isadev(dvp, &netmask); + for (dvp = isa_devtab_null; dvp; dvp++) + (void) config_isadev(dvp, (u_int *) NULL); +#include "sl.h" +#if NSL > 0 + netmask |= ttymask; + ttymask |= netmask; +#endif +/* printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask); */ + splnone(); +} + +/* + * Configure an ISA device. + */ +config_isadev(isdp, mp) + struct isa_device *isdp; + u_int *mp; +{ + struct isa_driver *dp; + static short drqseen, irqseen; + + if (dp = isdp->id_driver) { + /* if a device with i/o memory, convert to virtual address */ + if (isdp->id_maddr) { + extern unsigned int atdevbase; + + isdp->id_maddr -= IOM_BEGIN; + isdp->id_maddr += atdevbase; + } + isdp->id_alive = (*dp->probe)(isdp); + if (isdp->id_alive) { + + printf("%s%d at port 0x%x ", dp->name, + isdp->id_unit, isdp->id_iobase); + + /* check for conflicts */ + if (irqseen & isdp->id_irq) { + printf("INTERRUPT CONFLICT - irq%d\n", + ffs(isdp->id_irq) - 1); + return (0); + } + if (isdp->id_drq != -1 + && (drqseen & (1<<isdp->id_drq))) { + printf("DMA CONFLICT - drq%d\n", isdp->id_drq); + return (0); + } + /* NEED TO CHECK IOMEM CONFLICT HERE */ + + /* allocate and wire in device */ + if(isdp->id_irq) { + int intrno; + + intrno = ffs(isdp->id_irq)-1; + printf("irq %d ", intrno); + INTREN(isdp->id_irq); + if(mp)INTRMASK(*mp,isdp->id_irq); + setidt(NRSVIDT + intrno, isdp->id_intr, + SDT_SYS386IGT, SEL_KPL); + irqseen |= isdp->id_irq; + } + if (isdp->id_drq != -1) { + printf("drq %d ", isdp->id_drq); + drqseen |= 1 << isdp->id_drq; + } + + (*dp->attach)(isdp); + + printf("on isa\n"); + } + return (1); + } else return(0); +} +#else /* notyet */ +/* + * Configure all ISA devices + */ +isa_configure() { + struct isa_device *dvp; + struct isa_driver *dp; + + enable_intr(); + splhigh(); + INTREN(IRQ_SLAVE); + for (dvp = isa_devtab_tty; config_isadev(dvp,&ttymask); dvp++); + for (dvp = isa_devtab_bio; config_isadev(dvp,&biomask); dvp++); + for (dvp = isa_devtab_net; config_isadev(dvp,&netmask); dvp++); + for (dvp = isa_devtab_null; config_isadev(dvp,(u_int *) NULL); dvp++); +#include "sl.h" +#if NSL > 0 + netmask |= ttymask; + ttymask |= netmask; +#endif + /* biomask |= ttymask ; can some tty devices use buffers? */ + printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask); + splnone(); +} + +/* + * Configure an ISA device. + */ +config_isadev(isdp, mp) + struct isa_device *isdp; + u_int *mp; +{ + struct isa_driver *dp; + + if (dp = isdp->id_driver) { + if (isdp->id_maddr) { + extern u_int atdevbase; + + isdp->id_maddr -= 0xa0000; /* XXX should be a define */ + isdp->id_maddr += atdevbase; + } + isdp->id_alive = (*dp->probe)(isdp); + if (isdp->id_alive) { + printf("%s%d", dp->name, isdp->id_unit); + /* + * The attach should really be after all the printf's + * but until all the drivers are fixed do it here. + * There is a comment below that shows where this + * really belongs. Rod Grimes 04/10/93 + */ + (*dp->attach)(isdp); + /* + * Only print the I/O address range if id_alive != -1 + * Right now this is a temporary fix just for the new + * NPX code so that if it finds a 486 that can use trap + * 16 it will not report I/O addresses. + * Rod Grimes 04/26/94 + */ + if (isdp->id_alive != -1) { + printf(" at 0x%x", isdp->id_iobase); + if ((isdp->id_iobase + isdp->id_alive - 1) != + isdp->id_iobase) + printf("-0x%x", + isdp->id_iobase + + isdp->id_alive - 1); + } + if(isdp->id_irq) + printf(" irq %d", ffs(isdp->id_irq)-1); + if (isdp->id_drq != -1) + printf(" drq %d", isdp->id_drq); + if (isdp->id_maddr != 0) + printf(" maddr 0x%x", kvtop(isdp->id_maddr)); + if (isdp->id_msize != 0) + printf(" msize %d", isdp->id_msize); + if (isdp->id_flags != 0) + printf(" flags 0x%x", isdp->id_flags); + printf(" on isa\n"); + + /* This is the place the attach should be done! */ + if(isdp->id_irq) { + int intrno; + + intrno = ffs(isdp->id_irq)-1; + setidt(ICU_OFFSET+intrno, isdp->id_intr, + SDT_SYS386IGT, SEL_KPL); + if(mp) + INTRMASK(*mp,isdp->id_irq); + INTREN(isdp->id_irq); + } + } + return (1); + } else return(0); +} +#endif /* (!) notyet */ + +#define IDTVEC(name) __CONCAT(X,name) +/* default interrupt vector table entries */ +extern IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3), + IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7), + IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11), + IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15); + +static *defvec[16] = { + &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3), + &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7), + &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11), + &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) }; + +/* out of range default interrupt vector gate entry */ +extern IDTVEC(intrdefault); + +/* + * Fill in default interrupt table (in case of spuruious interrupt + * during configuration of kernel, setup interrupt control unit + */ +isa_defaultirq() { + int i; + + /* icu vectors */ + for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++) + setidt(i, defvec[i], SDT_SYS386IGT, SEL_KPL); + + /* out of range vectors */ + for (i = NRSVIDT; i < NIDT; i++) + setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL); + + /* initialize 8259's */ + outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ + outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */ + outb(IO_ICU1+1, 1<<2); /* slave on line 2 */ +#ifdef AUTO_EOI_1 + outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */ +#else + outb(IO_ICU1+1, 1); /* 8086 mode */ +#endif + outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ + outb(IO_ICU1, 0x0a); /* default to IRR on read */ + outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ + + outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ + outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */ + outb(IO_ICU2+1,2); /* my slave id is 2 */ +#ifdef AUTO_EOI_2 + outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */ +#else + outb(IO_ICU2+1,1); /* 8086 mode */ +#endif + outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ + outb(IO_ICU2, 0x0a); /* default to IRR on read */ +} + +/* region of physical memory known to be contiguous */ +vm_offset_t isaphysmem; +static caddr_t dma_bounce[8]; /* XXX */ +static char bounced[8]; /* XXX */ +#define MAXDMASZ 512 /* XXX */ + +/* high byte of address is stored in this port for i-th dma channel */ +static short dmapageport[8] = + { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; + +/* + * isa_dmacascade(): program 8237 DMA controller channel to accept + * external dma control by a board. + */ +void isa_dmacascade(unsigned chan) +{ + if (chan > 7) + panic("isa_dmacascade: impossible request"); + + /* set dma channel mode, and set dma channel mode */ + if ((chan & 4) == 0) { + outb(DMA1_MODE, DMA37MD_CASCADE | chan); + outb(DMA1_SMSK, chan); + } else { + outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3)); + outb(DMA2_SMSK, chan & 3); + } +} + +/* + * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment + * problems by using a bounce buffer. + */ +void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan) +{ vm_offset_t phys; + int waport; + caddr_t newaddr; + + if ( chan > 7 + || (chan < 4 && nbytes > (1<<16)) + || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1))) + panic("isa_dmastart: impossible request"); + + if (isa_dmarangecheck(addr, nbytes, chan)) { + if (dma_bounce[chan] == 0) + dma_bounce[chan] = + /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/ + (caddr_t) isaphysmem + NBPG*chan; + bounced[chan] = 1; + newaddr = dma_bounce[chan]; + *(int *) newaddr = 0; /* XXX */ + + /* copy bounce buffer on write */ + if (!(flags & B_READ)) + bcopy(addr, newaddr, nbytes); + addr = newaddr; + } + + /* translate to physical */ + phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr); + + if ((chan & 4) == 0) { + /* + * Program one of DMA channels 0..3. These are + * byte mode channels. + */ + /* set dma channel mode, and reset address ff */ + if (flags & B_READ) + outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan); + else + outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan); + outb(DMA1_FFC, 0); + + /* send start address */ + waport = DMA1_CHN(chan); + outb(waport, phys); + outb(waport, phys>>8); + outb(dmapageport[chan], phys>>16); + + /* send count */ + outb(waport + 1, --nbytes); + outb(waport + 1, nbytes>>8); + + /* unmask channel */ + outb(DMA1_SMSK, chan); + } else { + /* + * Program one of DMA channels 4..7. These are + * word mode channels. + */ + /* set dma channel mode, and reset address ff */ + if (flags & B_READ) + outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3)); + else + outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3)); + outb(DMA2_FFC, 0); + + /* send start address */ + waport = DMA2_CHN(chan - 4); + outb(waport, phys>>1); + outb(waport, phys>>9); + outb(dmapageport[chan], phys>>16); + + /* send count */ + nbytes >>= 1; + outb(waport + 2, --nbytes); + outb(waport + 2, nbytes>>8); + + /* unmask channel */ + outb(DMA2_SMSK, chan & 3); + } +} + +void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan) +{ + + /* copy bounce buffer on read */ + /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/ + if (bounced[chan]) { + bcopy(dma_bounce[chan], addr, nbytes); + bounced[chan] = 0; + } +} + +/* + * Check for problems with the address range of a DMA transfer + * (non-contiguous physical pages, outside of bus address space, + * crossing DMA page boundaries). + * Return true if special handling needed. + */ + +isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) { + vm_offset_t phys, priorpage = 0, endva; + u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1); + + endva = (vm_offset_t)round_page(va + length); + for (; va < (caddr_t) endva ; va += NBPG) { + phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va)); +#define ISARAM_END RAM_END + if (phys == 0) + panic("isa_dmacheck: no physical page present"); + if (phys > ISARAM_END) + return (1); + if (priorpage) { + if (priorpage + NBPG != phys) + return (1); + /* check if crossing a DMA page boundary */ + if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk) + return (1); + } + priorpage = phys; + } + return (0); +} + +/* head of queue waiting for physmem to become available */ +struct buf isa_physmemq; + +/* blocked waiting for resource to become free for exclusive use */ +static isaphysmemflag; +/* if waited for and call requested when free (B_CALL) */ +static void (*isaphysmemunblock)(); /* needs to be a list */ + +/* + * Allocate contiguous physical memory for transfer, returning + * a *virtual* address to region. May block waiting for resource. + * (assumed to be called at splbio()) + */ +caddr_t +isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) { + + isaphysmemunblock = func; + while (isaphysmemflag & B_BUSY) { + isaphysmemflag |= B_WANTED; + sleep(&isaphysmemflag, PRIBIO); + } + isaphysmemflag |= B_BUSY; + + return((caddr_t)isaphysmem); +} + +/* + * Free contiguous physical memory used for transfer. + * (assumed to be called at splbio()) + */ +void +isa_freephysmem(caddr_t va, unsigned length) { + + isaphysmemflag &= ~B_BUSY; + if (isaphysmemflag & B_WANTED) { + isaphysmemflag &= B_WANTED; + wakeup(&isaphysmemflag); + if (isaphysmemunblock) + (*isaphysmemunblock)(); + } +} + +/* + * Handle a NMI, possibly a machine check. + * return true to panic system, false to ignore. + */ +isa_nmi(cd) { + + log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70)); + return(0); +} + +/* + * Caught a stray interrupt, notify + */ +isa_strayintr(d) { + + /* DON'T BOTHER FOR NOW! */ + /* for some reason, we get bursts of intr #7, even if not enabled! */ + /* + * Well the reason you got bursts of intr #7 is because someone + * raised an interrupt line and dropped it before the 8259 could + * prioritize it. This is documented in the intel data book. This + * means you have BAD hardware! I have changed this so that only + * the first 5 get logged, then it quits logging them, and puts + * out a special message. rgrimes 3/25/1993 + */ + extern u_long intrcnt_stray; + + intrcnt_stray++; + if (intrcnt_stray <= 5) + log(LOG_ERR,"ISA strayintr %x\n", d); + if (intrcnt_stray == 5) + log(LOG_CRIT,"Too many ISA strayintr not logging any more\n"); +} + +/* + * Wait "n" microseconds. + * Relies on timer 1 counting down from (TIMER_FREQ / hz) at + * (2 * TIMER_FREQ) Hz. + * Note: timer had better have been programmed before this is first used! + * (The standard programming causes the timer to generate a square wave and + * the counter is decremented twice every cycle.) + */ +#define CF (2 * TIMER_FREQ) +#define TIMER_FREQ 1193182 /* XXX - should be elsewhere */ + +extern int hz; /* XXX - should be elsewhere */ + +int DELAY(n) + int n; +{ + int counter_limit; + int prev_tick; + int tick; + int ticks_left; + int sec; + int usec; + +#ifdef DELAYDEBUG + int getit_calls = 1; + int n1; + static int state = 0; + + if (state == 0) { + state = 1; + for (n1 = 1; n1 <= 10000000; n1 *= 10) + DELAY(n1); + state = 2; + } + if (state == 1) + printf("DELAY(%d)...", n); +#endif + + /* + * Read the counter first, so that the rest of the setup overhead is + * counted. Guess the initial overhead is 20 usec (on most systems it + * takes about 1.5 usec for each of the i/o's in getit(). The loop + * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The + * multiplications and divisions to scale the count take a while). + */ + prev_tick = getit(0, 0); + n -= 20; + + /* + * Calculate (n * (CF / 1e6)) without using floating point and without + * any avoidable overflows. + */ + sec = n / 1000000; + usec = n - sec * 1000000; + ticks_left = sec * CF + + usec * (CF / 1000000) + + usec * ((CF % 1000000) / 1000) / 1000 + + usec * (CF % 1000) / 1000000; + + counter_limit = TIMER_FREQ / hz; + while (ticks_left > 0) { + tick = getit(0, 0); +#ifdef DELAYDEBUG + ++getit_calls; +#endif + if (tick > prev_tick) + ticks_left -= prev_tick - (tick - counter_limit); + else + ticks_left -= prev_tick - tick; + prev_tick = tick; + } +#ifdef DELAYDEBUG + if (state == 1) + printf(" %d calls to getit() at %d usec each\n", + getit_calls, (n + 5) / getit_calls); +#endif +} + +getit(unit, timer) { + int high; + int low; + + /* + * XXX - isa.h defines bogus timers. There's no such timer as + * IO_TIMER_2 = 0x48. There's a timer in the CMOS RAM chip but + * its interface is quite different. Neither timer is an 8252. + * We actually only call this with unit = 0 and timer = 0. It + * could be static... + */ + /* + * Protect ourself against interrupts. + * XXX - sysbeep() and sysbeepstop() need protection. + */ + disable_intr(); + /* + * Latch the count for 'timer' (cc00xxxx, c = counter, x = any). + */ + outb(IO_TIMER1 + 3, timer << 6); + + low = inb(IO_TIMER1 + timer); + high = inb(IO_TIMER1 + timer); + enable_intr(); + return ((high << 8) | low); +} + +static beeping; +static +sysbeepstop(f) +{ + /* disable counter 2 */ + outb(0x61, inb(0x61) & 0xFC); + if (f) + timeout(sysbeepstop, 0, f); + else + beeping = 0; +} + +void sysbeep(int pitch, int period) +{ + + outb(0x61, inb(0x61) | 3); /* enable counter 2 */ + /* + * XXX - move timer stuff to clock.c. + * Program counter 2: + * ccaammmb, c counter, a = access, m = mode, b = BCD + * 1011x110, 11 for aa = LSB then MSB, x11 for mmm = square wave. + */ + outb(0x43, 0xb6); /* set command for counter 2, 2 byte write */ + + outb(0x42, pitch); + outb(0x42, (pitch>>8)); + + if (!beeping) { + beeping = period; + timeout(sysbeepstop, period/2, period); + } +} + +/* + * Pass command to keyboard controller (8042) + */ +unsigned kbc_8042cmd(val) { + + while (inb(KBSTATP)&KBS_IBF); + if (val) outb(KBCMDP, val); + while (inb(KBSTATP)&KBS_IBF); + return (inb(KBDATAP)); +} + +/* + * find an ISA device in a given isa_devtab_* table, given + * the table to search, the expected id_driver entry, and the unit number. + * + * this function is defined in isa_device.h, and this location is debatable; + * i put it there because it's useless w/o, and directly operates on + * the other stuff in that file. + * + */ + +struct isa_device *find_isadev(table, driverp, unit) + struct isa_device *table; + struct isa_driver *driverp; + int unit; +{ + if (driverp == NULL) /* sanity check */ + return NULL; + + while ((table->id_driver != driverp) || (table->id_unit != unit)) { + if (table->id_driver == 0) + return NULL; + + table++; + } + + return table; +} + +/* + * Return nonzero if a (masked) irq is pending for a given device. + */ +int +isa_irq_pending(dvp) + struct isa_device *dvp; +{ + unsigned id_irq; + + id_irq = (unsigned short) dvp->id_irq; /* XXX silly type in struct */ + if (id_irq & 0xff) + return (inb(IO_ICU1) & id_irq); + return (inb(IO_ICU2) & (id_irq >> 8)); +} diff --git a/sys/i386/isa/isa.h b/sys/i386/isa/isa.h new file mode 100644 index 000000000000..a9c042d4e542 --- /dev/null +++ b/sys/i386/isa/isa.h @@ -0,0 +1,188 @@ +/*- + * 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. + * + * @(#)isa.h 5.7 (Berkeley) 5/9/91 + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 3 00158 + * -------------------- ----- ---------------------- + * + * 15 Feb 93 Julian Elischer Added entries for some scsi adapters + * 06 Apr 93 Rodney W. Grimes Added com3 and com4, added IO_ISASIZES + * section + * 26 Apr 93 Bruce Evans Support for intr-0.1 + */ + +/* + * ISA Bus conventions + */ + +#ifndef LOCORE +#include <sys/cdefs.h> + +unsigned char rtcin __P((int)); +extern unsigned int atdevbase; /* offset in virtual memory of ISA io mem */ +void sysbeep __P((int, int)); +unsigned kbd_8042cmd __P((int)); +struct isa_device; +int isa_irq_pending __P((struct isa_device *dvp)); +#endif + + +/* + * Input / Output Port Assignments + */ + +#ifndef IO_BEGIN +#define IO_ISABEGIN 0x000 /* 0x000 - Beginning of I/O Registers */ + + /* CPU Board */ +#define IO_DMA1 0x000 /* 8237A DMA Controller #1 */ +#define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */ +#define IO_TIMER1 0x040 /* 8252 Timer #1 */ +#define IO_TIMER2 0x048 /* 8252 Timer #2 */ +#define IO_KBD 0x060 /* 8042 Keyboard */ +#define IO_RTC 0x070 /* RTC */ +#define IO_NMI IO_RTC /* NMI Control */ +#define IO_DMAPG 0x080 /* DMA Page Registers */ +#define IO_ICU2 0x0A0 /* 8259A Interrupt Controller #2 */ +#define IO_DMA2 0x0C0 /* 8237A DMA Controller #2 */ +#define IO_NPX 0x0F0 /* Numeric Coprocessor */ + + /* Cards */ + /* 0x100 - 0x16F Open */ + +#define IO_WD2 0x170 /* Secondary Fixed Disk Controller */ + + /* 0x178 - 0x1EF Open */ + +#define IO_WD1 0x1f0 /* Primary Fixed Disk Controller */ +#define IO_GAME 0x200 /* Game Controller */ + + /* 0x208 - 0x277 Open */ + +#define IO_LPT2 0x278 /* Parallel Port #2 */ + + /* 0x280 - 0x2E7 Open */ + +#define IO_COM4 0x2e8 /* COM4 i/o address */ + + /* 0x2F0 - 0x2F7 Open */ + +#define IO_COM2 0x2f8 /* COM2 i/o address */ + /* 0x300 - 0x32F Open */ + +#define IO_BT0 0x330 /* bustek 742a default addr. */ +#define IO_AHA0 0x330 /* adaptec 1542 default addr. */ +#define IO_UHA0 0x330 /* ultrastore 14f default addr. */ +#define IO_BT1 0x334 /* bustek 742a default addr. */ +#define IO_AHA1 0x334 /* adaptec 1542 default addr. */ + /* 0x338 - 0x36F Open */ + +#define IO_FD2 0x370 /* secondary base i/o address */ +#define IO_LPT1 0x378 /* Parallel Port #1 */ + + /* 0x380 - 0x3AF Open */ + +#define IO_MDA 0x3B0 /* Monochome Adapter */ +#define IO_LPT3 0x3BC /* Monochome Adapter Printer Port */ +#define IO_VGA 0x3C0 /* E/VGA Ports */ +#define IO_CGA 0x3D0 /* CGA Ports */ + + /* 0x3E0 - 0x3E7 Open */ + +#define IO_COM3 0x3e8 /* COM3 i/o address */ +#define IO_FD1 0x3f0 /* primary base i/o address */ +#define IO_COM1 0x3f8 /* COM1 i/o address */ + +#define IO_ISAEND 0x3FF /* - 0x3FF End of I/O Registers */ +#endif IO_ISABEGIN + +/* + * Input / Output Port Sizes - these are from several sources, and tend + * to be the larger of what was found, ie COM ports can be 4, but some + * boards do not fully decode the address, thus 8 ports are used. + */ + +#ifndef IO_ISASIZES +#define IO_ISASIZES + +#define IO_COMSIZE 8 /* 8250, 16X50 com controllers (4?) */ +#define IO_CGASIZE 16 /* CGA controllers */ +#define IO_DMASIZE 16 /* 8237 DMA controllers */ +#define IO_DPGSIZE 32 /* 74LS612 DMA page reisters */ +#define IO_FDCSIZE 8 /* Nec765 floppy controllers */ +#define IO_WDCSIZE 8 /* WD compatible disk controllers */ +#define IO_GAMSIZE 16 /* AT compatible game controllers */ +#define IO_ICUSIZE 16 /* 8259A interrupt controllers */ +#define IO_KBDSIZE 16 /* 8042 Keyboard controllers */ +#define IO_LPTSIZE 8 /* LPT controllers, some use only 4 */ +#define IO_MDASIZE 16 /* Monochrome display controllers */ +#define IO_RTCSIZE 16 /* CMOS real time clock, NMI control */ +#define IO_TMRSIZE 16 /* 8253 programmable timers */ +#define IO_NPXSIZE 16 /* 80387/80487 NPX registers */ +#define IO_VGASIZE 16 /* VGA controllers */ + +#endif /* IO_ISASIZES */ + +/* + * Input / Output Memory Physical Addresses + */ + +#ifndef IOM_BEGIN +#define IOM_BEGIN 0x0a0000 /* Start of I/O Memory "hole" */ +#define IOM_END 0x100000 /* End of I/O Memory "hole" */ +#define IOM_SIZE (IOM_END - IOM_BEGIN) +#endif IOM_BEGIN + +/* + * RAM Physical Address Space (ignoring the above mentioned "hole") + */ + +#ifndef RAM_BEGIN +#define RAM_BEGIN 0x0000000 /* Start of RAM Memory */ +#define RAM_END 0x1000000 /* End of RAM Memory */ +#define RAM_SIZE (RAM_END - RAM_BEGIN) +#endif RAM_BEGIN + +/* + * Oddball Physical Memory Addresses + */ +#ifndef COMPAQ_RAMRELOC +#define COMPAQ_RAMRELOC 0x80c00000 /* Compaq RAM relocation/diag */ +#define COMPAQ_RAMSETUP 0x80c00002 /* Compaq RAM setup */ +#define WEITEK_FPU 0xC0000000 /* WTL 2167 */ +#define CYRIX_EMC 0xC0000000 /* Cyrix EMC */ +#endif COMPAQ_RAMRELOC diff --git a/sys/i386/isa/isa_device.h b/sys/i386/isa/isa_device.h new file mode 100644 index 000000000000..eea71ecf8286 --- /dev/null +++ b/sys/i386/isa/isa_device.h @@ -0,0 +1,85 @@ +/*- + * 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. + * + * @(#)isa_device.h 7.1 (Berkeley) 5/9/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 2 00163 + * -------------------- ----- ---------------------- + * + * 27 Feb 93 Chris Demetriou Add proper flag handling. + * 10 Mar 93 Rodney W. Grimes Fixed isa_device->id_irq to be + * the u_short instead of short. This + * enables us to use irq15! + * 27 May 93 Guido van Rooij Add prototype find_isadev() + * + */ + +/* + * ISA Bus Autoconfiguration + */ + +/* + * Per device structure. + */ +struct isa_device { + struct isa_driver *id_driver; + short id_iobase; /* base i/o address */ + u_short id_irq; /* interrupt request */ + short id_drq; /* DMA request */ + caddr_t id_maddr; /* physical i/o memory address on bus (if any)*/ + int id_msize; /* size of i/o memory */ + int (*id_intr)(); /* interrupt interface routine */ + int id_unit; /* unit number */ + int id_flags; /* flags */ + int id_scsiid; /* scsi id if needed */ + int id_alive; /* device is present */ +}; + +/* + * Per-driver structure. + * + * Each device driver defines entries for a set of routines + * as well as an array of types which are acceptable to it. + * These are used at boot time by the configuration program. + */ +struct isa_driver { + int (*probe)(); /* test whether device is present */ + int (*attach)(); /* setup driver for a device */ + char *name; /* device name */ +}; + +extern struct isa_device isa_devtab_bio[], isa_devtab_tty[], isa_devtab_net[], + isa_devtab_null[]; + +extern struct isa_device *find_isadev(/* table, driver, unit*/); diff --git a/sys/i386/isa/kbd.h b/sys/i386/isa/kbd.h new file mode 100644 index 000000000000..f60e8c232150 --- /dev/null +++ b/sys/i386/isa/kbd.h @@ -0,0 +1,58 @@ +/* + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00162 + * -------------------- ----- ---------------------- + * + * 26 May 93 Holger Veit added more 8042 defines + * + * Keyboard definitions + */ + +/* Reference: IBM AT Technical Reference Manual, + * pp. 1-38 to 1-43, 4-3 to 4-22 + */ + +/* commands sent to KBCMDP */ + +#define KBC_CMDREAD 0x20 /* read kbd cntrl command byte */ +#define KBC_CMDWRITE 0x60 /* == LD_CMDBYTE in kd.h, write command */ +#define KBC_SELFTEST 0xAA /* perform self test, returns 55 when ok */ +#define KBC_IFTEST 0xAB /* perform interface test */ +#define KBC_DIAGDUMP 0xAC /* send 19 status bytes to system */ +#define KBC_DISKBD 0xAD /* disable keyboard */ +#define KBC_ENAKBD 0xAE /* enable keyboard */ +#define KBC_RDINP 0xC0 /* read input port */ +#define KBC_RDID 0xC4 /* read keyboard ID */ +#define KBC_RDOUTP 0xD0 /* read output port */ +#define KBC_WROUTP 0xD1 /* write output port */ +#define KBC_RDTINP 0xE0 /* read test inputs */ + +/* commands sent to KBDATAP */ +#define KBC_STSIND 0xED /* set keyboard status indicators */ +#define KBC_ECHO 0xEE /* reply with 0xEE */ +#define KBC_SETTPM 0xF3 /* Set typematic rate/delay */ +#define KBC_ENABLE 0xF4 /* Start scanning */ +#define KBC_SETDEFD 0xF5 /* =KBC_SETDEF, but disable scanning */ +#define KBC_SETDEF 0xF6 /* Set power on defaults */ +#define KBC_RESEND 0xFE /* system wants keyboard to resend last code */ +#define KBC_RESET 0xFF /* Reset the keyboard */ + +/* responses */ +#define KBR_OVERRUN 0x00 /* Keyboard flooded */ +#define KBR_STOK 0x55 /* Selftest ok response */ +#define KBR_IFOK 0x00 /* Interface test ok */ +#define KBR_IFCL_SA0 0x01 /* Clock Stuck-at-0 fault */ +#define KBR_IFCL_SA1 0x02 /* Clock Stuck-at-1 fault */ +#define KBR_IFDA_SA0 0x03 /* Data Stuck-at-0 fault */ +#define KBR_IFDA_SA1 0x04 /* Data Stuck-at-1 fault */ +#define KBR_RSTDONE 0xAA /* Keyboard reset (BAT) complete */ +#define KBR_E0 0xE0 /* Extended prefix */ +#define KBR_E1 0xE1 /* BREAK'S HIT :-( */ +#define KBR_ECHO 0xEE /* Echo response */ +#define KBR_F0 0xF0 /* Break code prefix */ +#define KBR_ACK 0xFA /* Keyboard did receive command */ +#define KBR_BATFAIL 0xFC /* BAT failed */ +#define KBR_DIAGFAIL 0xFD /* Diagnostic failed response */ +#define KBR_RESEND 0xFE /* Keyboard needs resend of command */ diff --git a/sys/i386/isa/lpt.c b/sys/i386/isa/lpt.c new file mode 100644 index 000000000000..46d1e47c4a07 --- /dev/null +++ b/sys/i386/isa/lpt.c @@ -0,0 +1,455 @@ +/* + * 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. + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 2 00164 + * -------------------- ----- ---------------------- + * + * 06 Apr 93 Eric Haug Fixed comments and includes. [Ed: I did + * not include the unit-1 thing, that is a + * DOSism, fixed the config file instead] + * 06 Apr 93 Rodney W. Grimes A real probe routine, may even cause on + * interrupt if a printer is attached. + * + * 01 Jun 93 Rodney W. Grimes Made lpflag uniq now is lptflag + * Added timeout loop to lpt_port_test. + * lpt_port_test should move to a common + * routine.. + * + */ + +/* + * Device Driver for AT parallel printer port + * Written by William Jolitz 12/18/90 + */ + +#include "lpt.h" +#if NLPT > 0 + +#include "param.h" +#include "systm.h" +#include "proc.h" +#include "user.h" +#include "buf.h" +#include "kernel.h" +#include "ioctl.h" +#include "tty.h" +#include "uio.h" + +#include "i386/isa/isa.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/lptreg.h" + +#define LPINITRDY 4 /* wait up to 4 seconds for a ready */ +#define LPTOUTTIME 4 /* wait up to 4 seconds for a ready */ +#define LPPRI (PZERO+8) +#define BUFSIZE 1024 + +#ifndef DEBUG +#define lprintf +#else +#define lprintf if (lptflag) printf +int lptflag = 1; +#endif + +int lptout(); +#ifdef DEBUG +int lptflag = 1; +#endif + +int lptprobe(), lptattach(), lptintr(); + +struct isa_driver lptdriver = { + lptprobe, lptattach, "lpt" +}; + +#define LPTUNIT(s) (((s)>>6)&0x3) +#define LPTFLAGS(s) ((s)&0x3f) + +struct lpt_softc { + short sc_port; + short sc_state; + /* default case: negative prime, negative ack, handshake strobe, + prime once */ + u_char sc_control; + char sc_flags; +#define LP_POS_INIT 0x01 /* if we are a postive init signal */ +#define LP_POS_ACK 0x02 /* if we are a positive going ack */ +#define LP_NO_PRIME 0x04 /* don't prime the printer at all */ +#define LP_PRIMEOPEN 0x08 /* prime on every open */ +#define LP_AUTOLF 0x10 /* tell printer to do an automatic lf */ +#define LP_BYPASS 0x20 /* bypass printer ready checks */ + struct buf *sc_inbuf; + short sc_xfercnt ; + char sc_primed; + char *sc_cp ; +} lpt_sc[NLPT] ; + +/* bits for state */ +#define OPEN (1<<0) /* device is open */ +#define ASLP (1<<1) /* awaiting draining of printer */ +#define ERROR (1<<2) /* error was received from printer */ +#define OBUSY (1<<3) /* printer is busy doing output */ +#define LPTOUT (1<<4) /* timeout while not selected */ +#define TOUT (1<<5) /* timeout while not selected */ +#define INIT (1<<6) /* waiting to initialize for open */ + +/* + * Internal routine to lptprobe to do port tests of one byte value + */ +int +lpt_port_test(short port, u_char data, u_char mask) + { + int temp, timeout; + + data = data & mask; + outb(port, data); + timeout = 100; + do + temp = inb(port) & mask; + while (temp != data && --timeout); + lprintf("Port 0x%x\tout=%x\tin=%x\n", port, data, temp); + return (temp == data); + } + +/* + * New lptprobe routine written by Rodney W. Grimes, 3/25/1993 + * + * 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 + */ + +int +lptprobe(struct isa_device *dvp) + { + int status; + short port; + u_char data; + u_char mask; + int i; + + status = IO_LPTSIZE; + + port = dvp->id_iobase + lpt_data; + mask = 0xff; + while (mask != 0) + { + data = 0x55; /* Alternating zeros */ + if (!lpt_port_test(port, data, mask)) status = 0; + + data = 0xaa; /* Alternating ones */ + if (!lpt_port_test(port, data, mask)) status = 0; + + for (i = 0; i < 8; i++) /* Walking zero */ + { + data = ~(1 << i); + if (!lpt_port_test(port, data, mask)) status = 0; + } + + for (i = 0; i < 8; i++) /* Walking one */ + { + data = (1 << i); + if (!lpt_port_test(port, data, mask)) status = 0; + } + + if (port == dvp->id_iobase + lpt_data) + { + port = dvp->id_iobase + lpt_control; + mask = 0x1e; + } + else + mask = 0; + } + outb(dvp->id_iobase+lpt_data, 0); + outb(dvp->id_iobase+lpt_control, 0); + return (status); + } + +lptattach(isdp) + struct isa_device *isdp; +{ + struct lpt_softc *sc; + + sc = lpt_sc + isdp->id_unit; + sc->sc_port = isdp->id_iobase; + outb(sc->sc_port+lpt_control, LPC_NINIT); + return (1); +} + +/* + * lptopen -- reset the printer, then wait until it's selected and not busy. + */ + +lptopen(dev, flag) + dev_t dev; + int flag; +{ + struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev)); + int s; + int trys, port; + + if (sc->sc_state) { +lprintf("lp: still open\n") ; +printf("still open %x\n", sc->sc_state); + return(EBUSY); + } else sc->sc_state |= INIT; + + s = spltty(); + sc->sc_flags = LPTFLAGS(minor(dev)); +lprintf("lp flags 0x%x\n", sc->sc_flags); + port = sc->sc_port; + + /* init printer */ + if((sc->sc_flags & LP_NO_PRIME) == 0) { + if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) { + outb(port+lpt_control, 0); + sc->sc_primed++; + DELAY(500); + } + } + outb(port+lpt_control, LPC_SEL|LPC_NINIT); + + /* wait till ready (printer running diagnostics) */ + trys = 0; + do { + /* ran out of waiting for the printer */ + if (trys++ >= LPINITRDY*4) { + splx(s); + sc->sc_state = 0; +printf ("status %x\n", inb(port+lpt_status) ); + return (EBUSY); + } + + /* wait 1/4 second, give up if we get a signal */ + if (tsleep (sc, LPPRI|PCATCH, "lptinit", hz/4) != EWOULDBLOCK) { + sc->sc_state = 0; + splx(s); + return (EBUSY); + } + + /* is printer online and ready for output */ + } while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != + (LPS_SEL|LPS_NBSY|LPS_NERR)); + + if(sc->sc_flags&LP_AUTOLF) { + outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL); + sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL; + } else { + outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA); + sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA; + } + + sc->sc_state = OPEN | TOUT; + sc->sc_inbuf = geteblk(BUFSIZE); + sc->sc_xfercnt = 0; + splx(s); + timeout (lptout, sc, hz/2); +lprintf("opened.\n"); + return(0); +} + +lptout (sc) + struct lpt_softc *sc; +{ int pl; + +lprintf ("T %x ", inb(sc->sc_port+lpt_status)); + if (sc->sc_state&OPEN) + timeout (lptout, sc, hz/2); + else sc->sc_state &= ~TOUT; + + if (sc->sc_state & ERROR) + sc->sc_state &= ~ERROR; + + /* + * Avoid possible hangs do to missed interrupts + */ + if (sc->sc_xfercnt) { + pl = spltty(); + lptintr(sc - lpt_sc); + splx(pl); + } else { + sc->sc_state &= ~OBUSY; + wakeup((caddr_t)sc); + } +} + +/* + * lptclose -- close the device, free the local line buffer. + */ + +lptclose(dev, flag) + int flag; +{ + struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev)); + int port = sc->sc_port; + + sc->sc_state &= ~OPEN; + while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != + (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt) + /* wait 1/4 second, give up if we get a signal */ + if (tsleep (sc, LPPRI|PCATCH, "lpclose", hz) != EWOULDBLOCK) + break; + + sc->sc_state = 0; + sc->sc_xfercnt = 0; + outb(sc->sc_port+lpt_control, LPC_NINIT); + brelse(sc->sc_inbuf); +lprintf("closed.\n"); + return(0); +} + +/* + * lptwrite --copy a line from user space to a local buffer, then call + * putc to get the chars moved to the output queue. + */ + +lptwrite(dev, uio) + dev_t dev; + struct uio *uio; +{ + register unsigned n; + int pl, err; + struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev)); + + while (n = MIN(BUFSIZE, uio->uio_resid)) { + sc->sc_cp = sc->sc_inbuf->b_un.b_addr ; + uiomove(sc->sc_cp, n, uio); + sc->sc_xfercnt = n ; + while (sc->sc_xfercnt > 0) { + /* if the printer is ready for a char, give it one */ + if ((sc->sc_state & OBUSY) == 0){ +lprintf("\nC %d. ", sc->sc_xfercnt); + pl = spltty(); + lptintr(sc - lpt_sc); + (void) splx(pl); + } +lprintf("W "); + if (err = tsleep (sc, LPPRI|PCATCH, "lpwrite", 0)) + return(err); + } + } + return(0); +} + +/* + * lptintr -- handle printer interrupts which occur when the printer is + * ready to accept another char. + */ + +lptintr(unit) +{ + struct lpt_softc *sc = lpt_sc + unit; + int port = sc->sc_port,sts; + + /* is printer online and ready for output */ + if (((sts=inb(port+lpt_status)) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR/*|LPS_NACK*/)) == + (LPS_SEL|LPS_NBSY|LPS_NERR)) { + /* is this a false interrupt ? */ + if ((sc->sc_state & OBUSY) + && (sts & LPS_NACK) == 0) return; + sc->sc_state |= OBUSY; sc->sc_state &= ~ERROR; + + if (sc->sc_xfercnt) { + /* send char */ +/*lprintf("%x ", *sc->sc_cp); */ + outb(port+lpt_data, *sc->sc_cp++) ; sc->sc_xfercnt-- ; + outb(port+lpt_control, sc->sc_control|LPC_STB); + /* DELAY(X) */ + outb(port+lpt_control, sc->sc_control); + } + + /* any more bytes for the printer? */ + if (sc->sc_xfercnt > 0) return; + + /* none, wake up the top half to get more */ + sc->sc_state &= ~OBUSY; + wakeup((caddr_t)sc); +lprintf("w "); +return; + } else sc->sc_state |= ERROR; +lprintf("sts %x ", sts); +} + +int +lptioctl(dev_t dev, int cmd, caddr_t data, int flag) +{ + int error; + + error = 0; + switch (cmd) { +#ifdef THISISASAMPLE + case XXX: + dothis; andthis; andthat; + error=x; + break; +#endif /* THISISASAMPLE */ + default: + error = ENODEV; + } + + return(error); +} + +#endif /* NLPT */ diff --git a/sys/i386/isa/lptreg.h b/sys/i386/isa/lptreg.h new file mode 100644 index 000000000000..2605fa0ec163 --- /dev/null +++ b/sys/i386/isa/lptreg.h @@ -0,0 +1,34 @@ +/*- + * 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. + * + * %sccs.include.noredist.c% + * + * @(#)lptreg.h 1.1 (Berkeley) 12/19/90 + */ + +/* + * AT Parallel Port (for lineprinter) + * Interface port and bit definitions + * Written by William Jolitz 12/18/90 + * Copyright (C) William Jolitz 1990 + */ + +#define lpt_data 0 /* Data to/from printer (R/W) */ + +#define lpt_status 1 /* Status of printer (R) */ +#define LPS_NERR 0x08 /* printer no error */ +#define LPS_SEL 0x10 /* printer selected */ +#define LPS_OUT 0x20 /* printer out of paper */ +#define LPS_NACK 0x40 /* printer no ack of data */ +#define LPS_NBSY 0x80 /* printer no ack of data */ + +#define lpt_control 2 /* Control printer (R/W) */ +#define LPC_STB 0x01 /* strobe data to printer */ +#define LPC_AUTOL 0x02 /* automatic linefeed */ +#define LPC_NINIT 0x04 /* initialize printer */ +#define LPC_SEL 0x08 /* printer selected */ +#define LPC_ENA 0x10 /* printer out of paper */ diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c new file mode 100644 index 000000000000..73392fabfc5e --- /dev/null +++ b/sys/i386/isa/npx.c @@ -0,0 +1,564 @@ +/*- + * Copyright (c) 1990 William Jolitz. + * 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. + * + * @(#)npx.c 7.2 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00154 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Bruce Evans New npx-0.5 code + * 23 May 93 Rodney W. Grimes Return a special value of -1 from + * the probe code to keep isa_config from + * printing out the I/O address when we + * are using trap 16 handling. + * + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/isa/RCS/npx.c,v 1.2 92/01/21 14:34:27 william Exp $"; + +#include "npx.h" +#if NNPX > 0 + +#include "param.h" +#include "systm.h" +#include "conf.h" +#include "file.h" +#include "proc.h" +#include "machine/cpu.h" +#include "machine/pcb.h" +#include "machine/trap.h" +#include "ioctl.h" +#include "machine/specialreg.h" +#include "i386/isa/icu.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/isa.h" + +/* + * 387 and 287 Numeric Coprocessor Extension (NPX) Driver. + */ + +#ifdef __GNUC__ + +#define disable_intr() __asm("cli") +#define enable_intr() __asm("sti") +#define fldcw(addr) __asm("fldcw %0" : : "m" (*addr)) +#define fnclex() __asm("fnclex") +#define fninit() __asm("fninit") +#define fnsave(addr) __asm("fnsave %0" : "=m" (*addr) : "0" (*addr)) +#define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr)) +#define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr)) +#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fwait") +#define frstor(addr) __asm("frstor %0" : : "m" (*addr)) +#define fwait() __asm("fwait") +#define read_eflags() ({u_long ef; \ + __asm("pushf; popl %0" : "=a" (ef)); \ + ef; }) +#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \ + : : "n" (CR0_TS) : "ax") +#define stop_emulating() __asm("clts") +#define write_eflags(ef) __asm("pushl %0; popf" : : "a" ((u_long) ef)) + +#else /* not __GNUC__ */ + +void disable_intr __P((void)); +void enable_intr __P((void)); +void fldcw __P((caddr_t addr)); +void fnclex __P((void)); +void fninit __P((void)); +void fnsave __P((caddr_t addr)); +void fnstcw __P((caddr_t addr)); +void fnstsw __P((caddr_t addr)); +void fp_divide_by_0 __P((void)); +void frstor __P((caddr_t addr)); +void fwait __P((void)); +u_long read_eflags __P((void)); +void start_emulating __P((void)); +void stop_emulating __P((void)); +void write_eflags __P((u_long ef)); + +#endif /* __GNUC__ */ + +typedef u_char bool_t; + +extern struct gate_descriptor idt[]; + +int npxdna __P((void)); +void npxexit __P((struct proc *p)); +void npxinit __P((u_int control)); +void npxintr __P((struct intrframe frame)); +void npxsave __P((struct save87 *addr)); +static int npxattach __P((struct isa_device *dvp)); +static int npxprobe __P((struct isa_device *dvp)); +static int npxprobe1 __P((struct isa_device *dvp)); + +struct isa_driver npxdriver = { + npxprobe, npxattach, "npx", +}; + +u_int npx0mask; +struct proc *npxproc; + +static bool_t npx_ex16; +static bool_t npx_exists; +static struct gate_descriptor npx_idt_probeintr; +static int npx_intrno; +static volatile u_int npx_intrs_while_probing; +static bool_t npx_irq13; +static volatile u_int npx_traps_while_probing; + +/* + * Special interrupt handlers. Someday intr0-intr15 will be used to count + * interrupts. We'll still need a special exception 16 handler. The busy + * latch stuff in probintr() can be moved to npxprobe(). + */ +void probeintr(void); +asm +(" + .text +_probeintr: + ss + incl _npx_intrs_while_probing + pushl %eax + movb $0x20,%al /* EOI (asm in strings loses cpp features) */ + outb %al,$0xa0 /* IO_ICU2 */ + outb %al,$0x20 /* IO_ICU1 */ + movb $0,%al + outb %al,$0xf0 /* clear BUSY# latch */ + popl %eax + iret +"); + +void probetrap(void); +asm +(" + .text +_probetrap: + ss + incl _npx_traps_while_probing + fnclex + iret +"); + +/* + * Probe routine. Initialize cr0 to give correct behaviour for [f]wait + * whether the device exists or not (XXX should be elsewhere). Set flags + * to tell npxattach() what to do. Modify device struct if npx doesn't + * need to use interrupts. Return 1 if device exists. + */ +static int +npxprobe(dvp) + struct isa_device *dvp; +{ + int result; + u_long save_eflags; + u_char save_icu1_mask; + u_char save_icu2_mask; + struct gate_descriptor save_idt_npxintr; + struct gate_descriptor save_idt_npxtrap; + /* + * This routine is now just a wrapper for npxprobe1(), to install + * special npx interrupt and trap handlers, to enable npx interrupts + * and to disable other interrupts. Someday isa_configure() will + * install suitable handlers and run with interrupts enabled so we + * won't need to do so much here. + */ + npx_intrno = NRSVIDT + ffs(dvp->id_irq) - 1; + save_eflags = read_eflags(); + disable_intr(); + save_icu1_mask = inb(IO_ICU1 + 1); + save_icu2_mask = inb(IO_ICU2 + 1); + save_idt_npxintr = idt[npx_intrno]; + save_idt_npxtrap = idt[16]; + outb(IO_ICU1 + 1, ~(IRQ_SLAVE | dvp->id_irq)); + outb(IO_ICU2 + 1, ~(dvp->id_irq >> 8)); + setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL); + setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL); + npx_idt_probeintr = idt[npx_intrno]; + enable_intr(); + result = npxprobe1(dvp); + disable_intr(); + outb(IO_ICU1 + 1, save_icu1_mask); + outb(IO_ICU2 + 1, save_icu2_mask); + idt[npx_intrno] = save_idt_npxintr; + idt[16] = save_idt_npxtrap; + write_eflags(save_eflags); + return (result); +} + +static int +npxprobe1(dvp) + struct isa_device *dvp; +{ + int control; + int status; +#ifdef lint + npxintr(); +#endif + /* + * Partially reset the coprocessor, if any. Some BIOS's don't reset + * it after a warm boot. + */ + outb(0xf1, 0); /* full reset on some systems, NOP on others */ + outb(0xf0, 0); /* clear BUSY# latch */ + /* + * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT + * instructions. We must set the CR0_MP bit and use the CR0_TS + * bit to control the trap, because setting the CR0_EM bit does + * not cause WAIT instructions to trap. It's important to trap + * WAIT instructions - otherwise the "wait" variants of no-wait + * control instructions would degenerate to the "no-wait" variants + * after FP context switches but work correctly otherwise. It's + * particularly important to trap WAITs when there is no NPX - + * otherwise the "wait" variants would always degenerate. + * + * Try setting CR0_NE to get correct error reporting on 486DX's. + * Setting it should fail or do nothing on lesser processors. + */ + load_cr0(rcr0() | CR0_MP | CR0_NE); + /* + * But don't trap while we're probing. + */ + stop_emulating(); + /* + * Finish resetting the coprocessor, if any. If there is an error + * pending, then we may get a bogus IRQ13, but probeintr() will handle + * it OK. Bogus halts have never been observed, but we enabled + * IRQ13 and cleared the BUSY# latch early to handle them anyway. + */ + fninit(); + DELAY(1000); /* wait for any IRQ13 (fwait might hang) */ +#ifdef DIAGNOSTIC + if (npx_intrs_while_probing != 0) + printf("fninit caused %u bogus npx interrupt(s)\n", + npx_intrs_while_probing); + if (npx_traps_while_probing != 0) + printf("fninit caused %u bogus npx trap(s)\n", + npx_traps_while_probing); +#endif + /* + * Check for a status of mostly zero. + */ + status = 0x5a5a; + fnstsw(&status); + if ((status & 0xb8ff) == 0) { + /* + * Good, now check for a proper control word. + */ + control = 0x5a5a; + fnstcw(&control); + if ((control & 0x1f3f) == 0x033f) { + npx_exists = 1; + /* + * We have an npx, now divide by 0 to see if exception + * 16 works. + */ + control &= ~(1 << 2); /* enable divide by 0 trap */ + fldcw(&control); + npx_traps_while_probing = npx_intrs_while_probing = 0; + fp_divide_by_0(); + if (npx_traps_while_probing != 0) { + /* + * Good, exception 16 works. + */ + npx_ex16 = 1; + dvp->id_irq = 0; /* zap the interrupt */ + /* + * special return value to flag that we do not + * actually use any I/O registers + */ + return (-1); + } + if (npx_intrs_while_probing != 0) { + /* + * Bad, we are stuck with IRQ13. + */ + npx_irq13 = 1; + npx0mask = dvp->id_irq; /* npxattach too late */ + return (IO_NPXSIZE); + } + /* + * Worse, even IRQ13 is broken. Use emulator. + */ + } + } + /* + * Probe failed, but we want to get to npxattach to initialize the + * emulator and say that it has been installed. XXX handle devices + * that aren't really devices better. + */ + dvp->id_irq = 0; + return (IO_NPXSIZE); +} + +/* + * Attach routine - announce which it is, and wire into system + */ +int +npxattach(dvp) + struct isa_device *dvp; +{ + if (npx_ex16) + printf(" <Errors reported via Exception 16>"); + else if (npx_irq13) + printf(" <Errors reported via IRQ 13>"); + else if (npx_exists) + printf(" <Error reporting broken, using 387 emulator>"); + else + printf(" <387 Emulator>"); + npxinit(__INITIAL_NPXCW__); + return (1); /* XXX unused */ +} + +/* + * Initialize floating point unit. + */ +void +npxinit(control) + u_int control; +{ + struct save87 dummy; + + if (!npx_exists) + return; + /* + * fninit has the same h/w bugs as fnsave. Use the detoxified + * fnsave to throw away any junk in the fpu. fnsave initializes + * the fpu and sets npxproc = NULL as important side effects. + */ + npxsave(&dummy); + stop_emulating(); + fldcw(&control); + if (curpcb != NULL) + fnsave(&curpcb->pcb_savefpu); + start_emulating(); +} + +/* + * Free coprocessor (if we have it). + */ +void +npxexit(p) + struct proc *p; +{ + + if (p == npxproc) { + start_emulating(); + npxproc = NULL; + } +} + +/* + * Record the FPU state and reinitialize it all except for the control word. + * Then generate a SIGFPE. + * + * Reinitializing the state allows naive SIGFPE handlers to longjmp without + * doing any fixups. + * + * XXX there is currently no way to pass the full error state to signal + * handlers, and if this is a nested interrupt there is no way to pass even + * a status code! So there is no way to have a non-naive SIGFPE handler. At + * best a handler could do an fninit followed by an fldcw of a static value. + * fnclex would be of little use because it would leave junk on the FPU stack. + * Returning from the handler would be even less safe than usual because + * IRQ13 exception handling makes exceptions even less precise than usual. + */ +void +npxintr(frame) + struct intrframe frame; +{ + int code; + + if (npxproc == NULL || !npx_exists) { + /* XXX no %p in stand/printf.c. Cast to quiet gcc -Wall. */ + printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n", + (u_long) npxproc, (u_long) curproc, npx_exists); + panic("npxintr from nowhere"); + } + if (npxproc != curproc) { + printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n", + (u_long) npxproc, (u_long) curproc, npx_exists); + panic("npxintr from non-current process"); + } + /* + * Save state. This does an implied fninit. It had better not halt + * the cpu or we'll hang. + */ + outb(0xf0, 0); + fnsave(&curpcb->pcb_savefpu); + fwait(); + /* + * Restore control word (was clobbered by fnsave). + */ + fldcw(&curpcb->pcb_savefpu.sv_env.en_cw); + fwait(); + /* + * Remember the exception status word and tag word. The current + * (almost fninit'ed) fpu state is in the fpu and the exception + * state just saved will soon be junk. However, the implied fninit + * doesn't change the error pointers or register contents, and we + * preserved the control word and will copy the status and tag + * words, so the complete exception state can be recovered. + */ + curpcb->pcb_savefpu.sv_ex_sw = curpcb->pcb_savefpu.sv_env.en_sw; + curpcb->pcb_savefpu.sv_ex_tw = curpcb->pcb_savefpu.sv_env.en_tw; + + /* + * Pass exception to process. + */ + if (ISPL(frame.if_cs) == SEL_UPL) { + /* + * Interrupt is essentially a trap, so we can afford to call + * the SIGFPE handler (if any) as soon as the interrupt + * returns. + * + * XXX little or nothing is gained from this, and plenty is + * lost - the interrupt frame has to contain the trap frame + * (this is otherwise only necessary for the rescheduling trap + * in doreti, and the frame for that could easily be set up + * just before it is used). + */ + curproc->p_regs = (int *)&frame.if_es; + curpcb->pcb_flags |= FM_TRAP; /* used by sendsig */ +#ifdef notyet + /* + * Encode the appropriate code for detailed information on + * this exception. + */ + code = XXX_ENCODE(curpcb->pcb_savefpu.sv_ex_sw); +#else + code = 0; /* XXX */ +#endif + trapsignal(curproc, SIGFPE, code); + curpcb->pcb_flags &= ~FM_TRAP; + } else { + /* + * Nested interrupt. These losers occur when: + * o an IRQ13 is bogusly generated at a bogus time, e.g.: + * o immediately after an fnsave or frstor of an + * error state. + * o a couple of 386 instructions after + * "fstpl _memvar" causes a stack overflow. + * These are especially nasty when combined with a + * trace trap. + * o an IRQ13 occurs at the same time as another higher- + * priority interrupt. + * + * Treat them like a true async interrupt. + */ + psignal(npxproc, SIGFPE); + } +} + +/* + * Implement device not available (DNA) exception + * + * It would be better to switch FP context here (only). This would require + * saving the state in the proc table instead of in the pcb. + */ +int +npxdna() +{ + if (!npx_exists) + return (0); + if (npxproc != NULL) { + printf("npxdna: npxproc = %lx, curproc = %lx\n", + (u_long) npxproc, (u_long) curproc); + panic("npxdna"); + } + stop_emulating(); + /* + * Record new context early in case frstor causes an IRQ13. + */ + npxproc = curproc; + /* + * The following frstor may cause an IRQ13 when the state being + * restored has a pending error. The error will appear to have been + * triggered by the current (npx) user instruction even when that + * instruction is a no-wait instruction that should not trigger an + * error (e.g., fnclex). On at least one 486 system all of the + * no-wait instructions are broken the same as frstor, so our + * treatment does not amplify the breakage. On at least one + * 386/Cyrix 387 system, fnclex works correctly while frstor and + * fnsave are broken, so our treatment breaks fnclex if it is the + * first FPU instruction after a context switch. + */ + frstor(&curpcb->pcb_savefpu); + + return (1); +} + +/* + * Wrapper for fnsave instruction to handle h/w bugs. If there is an error + * pending, then fnsave generates a bogus IRQ13 on some systems. Force + * any IRQ13 to be handled immediately, and then ignore it. This routine is + * often called at splhigh so it must not use many system services. In + * particular, it's much easier to install a special handler than to + * guarantee that it's safe to use npxintr() and its supporting code. + */ +void +npxsave(addr) + struct save87 *addr; +{ + u_char icu1_mask; + u_char icu2_mask; + u_char old_icu1_mask; + u_char old_icu2_mask; + struct gate_descriptor save_idt_npxintr; + + disable_intr(); + old_icu1_mask = inb(IO_ICU1 + 1); + old_icu2_mask = inb(IO_ICU2 + 1); + save_idt_npxintr = idt[npx_intrno]; + outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0mask)); + outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0mask >> 8)); + idt[npx_intrno] = npx_idt_probeintr; + enable_intr(); + stop_emulating(); + fnsave(addr); + fwait(); + start_emulating(); + npxproc = NULL; + disable_intr(); + icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */ + icu2_mask = inb(IO_ICU2 + 1); + outb(IO_ICU1 + 1, + (icu1_mask & ~npx0mask) | (old_icu1_mask & npx0mask)); + outb(IO_ICU2 + 1, + (icu2_mask & ~(npx0mask >> 8)) + | (old_icu2_mask & (npx0mask >> 8))); + idt[npx_intrno] = save_idt_npxintr; + enable_intr(); /* back to usual state */ +} + +#endif /* NNPX > 0 */ diff --git a/sys/i386/isa/rtc.h b/sys/i386/isa/rtc.h new file mode 100644 index 000000000000..2de060db24c1 --- /dev/null +++ b/sys/i386/isa/rtc.h @@ -0,0 +1,85 @@ +/*- + * 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. + * + * @(#)rtc.h 7.1 (Berkeley) 5/12/91 + */ + +/* + * RTC Register locations + */ + +#define RTC_SEC 0x00 /* seconds */ +#define RTC_SECALRM 0x01 /* seconds alarm */ +#define RTC_MIN 0x02 /* minutes */ +#define RTC_MINALRM 0x03 /* minutes alarm */ +#define RTC_HRS 0x04 /* hours */ +#define RTC_HRSALRM 0x05 /* hours alarm */ +#define RTC_WDAY 0x06 /* week day */ +#define RTC_DAY 0x07 /* day of month */ +#define RTC_MONTH 0x08 /* month of year */ +#define RTC_YEAR 0x09 /* month of year */ +#define RTC_STATUSA 0x0a /* status register A */ +#define RTCSA_TUP 0x80 /* time update, don't look now */ + +#define RTC_STATUSB 0x0b /* status register B */ + +#define RTC_INTR 0x0c /* status register C (R) interrupt source */ +#define RTCIR_UPDATE 0x10 /* update intr */ +#define RTCIR_ALARM 0x20 /* alarm intr */ +#define RTCIR_PERIOD 0x40 /* periodic intr */ +#define RTCIR_INT 0x80 /* interrupt output signal */ + +#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */ +#define RTCSD_PWR 0x80 /* clock lost power */ + +#define RTC_DIAG 0x0e /* status register E - bios diagnostic */ +#define RTCDG_BITS "\020\010clock_battery\007ROM_cksum\006config_unit\005memory_size\004fixed_disk\003invalid_time" + +#define RTC_RESET 0x0f /* status register F - reset code byte */ +#define RTCRS_RST 0x00 /* normal reset */ +#define RTCRS_LOAD 0x04 /* load system */ + +#define RTC_FDISKETTE 0x10 /* diskette drive type in upper/lower nibble */ +#define RTCFDT_NONE 0 /* none present */ +#define RTCFDT_360K 0x10 /* 360K */ +#define RTCFDT_12M 0x20 /* 1.2M */ +#define RTCFDT_144M 0x40 /* 1.44M */ + +#define RTC_BASELO 0x15 /* low byte of basemem size */ +#define RTC_BASEHI 0x16 /* high byte of basemem size */ +#define RTC_EXTLO 0x17 /* low byte of extended mem size */ +#define RTC_EXTHI 0x18 /* low byte of extended mem size */ + +#define RTC_CENTURY 0x32 /* current century - please increment in Dec99*/ diff --git a/sys/i386/isa/sio.c b/sys/i386/isa/sio.c new file mode 100644 index 000000000000..38503fd783bb --- /dev/null +++ b/sys/i386/isa/sio.c @@ -0,0 +1,1721 @@ +/*- + * 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. + * + * @(#)sio.c 7.5 (Berkeley) 5/16/91 + * + * 27 May 93 Bruce Evans From com-0.2 package, fast interrupt + * com port driver. + * 27 May 93 Guido van Rooij Ported in Chris Demetriou's BIDIR + * code, add multiport support. + * 27 May 93 Rodney W. Grimes I then renamed it to sio.c for putting + * into the patch kit. Added in sioselect + * from com.c. Added port 4 support. + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/isa/RCS/com.c,v 1.2 92/01/21 14:34:11 william Exp $"; + +#include "sio.h" +#if NSIO > 0 +/* + * COM driver, based on HP dca driver. + * Mostly rewritten to use pseudo-DMA. + * Works for National Semiconductor NS8250-NS16550AF UARTs. + */ +#include "param.h" +#include "systm.h" +#include "ioctl.h" +#include "tty.h" +#include "proc.h" +#include "user.h" +#include "conf.h" +#include "file.h" +#include "uio.h" +#include "kernel.h" +#include "syslog.h" + +#include "i386/isa/isa.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/comreg.h" +#include "i386/isa/ic/ns16550.h" + +#undef CRTS_IFLOW +#define CRTS_IFLOW CRTSCTS /* XXX, CCTS_OFLOW = CRTSCTS already */ +#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ +#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE) +#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8) +#define RS_IBUFSIZE 256 +#define TS_RTSBLOCK TS_TBLOCK /* XXX */ +#define TTY_BI TTY_FE /* XXX */ +#define TTY_OE TTY_PE /* XXX */ +#ifndef COM_BIDIR +#define UNIT(x) (minor(x)) /* XXX */ +#else /* COM_BIDIR */ +#define COM_UNITMASK 0x7f +#define COM_CALLOUTMASK 0x80 + +#define UNIT(x) (minor(x) & COM_UNITMASK) +#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK) +#endif /* COM_BIDIR */ + +#ifdef COM_MULTIPORT +/* checks in flags for multiport and which is multiport "master chip" + * for a given card + */ +#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01) +#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff) +#endif /* COM_MULTIPORT */ + +#define com_scr 7 /* scratch register for 16450-16550 (R/W) */ +#define schedsoftcom() (ipending |= 1 << 4) /* XXX */ + +/* + * Input buffer watermarks. + * The external device is asked to stop sending when the buffer exactly reaches + * high water, or when the high level requests it. + * The high level is notified immediately (rather than at a later clock tick) + * when this watermark is reached. + * The buffer size is chosen so the watermark should almost never be reached. + * The low watermark is invisibly 0 since the buffer is always emptied all at + * once. + */ +#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4) + +/* + * com state bits. + * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher + * than the other bits so that they can be tested as a group without masking + * off the low bits. + * + * The following com and tty flags correspond closely: + * TS_BUSY = CS_BUSY (maintained by comstart() and comflush()) + * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop()) + * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam()) + * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam()) + * TS_FLUSH is not used. + * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. + */ +#define CS_BUSY 0x80 /* output in progress */ +#define CS_TTGO 0x40 /* output not stopped by XOFF */ +#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */ +#define CS_CHECKMSR 1 /* check of MSR scheduled */ +#define CS_CTS_OFLOW 2 /* use CTS output flow control */ +#define CS_ODONE 4 /* output completed */ +#define CS_RTS_IFLOW 8 /* use RTS input flow control */ + +static char *error_desc[] = { +#define CE_OVERRUN 0 + "silo overflow", +#define CE_INTERRUPT_BUF_OVERFLOW 1 + "interrupt-level buffer overflow", +#define CE_TTY_BUF_OVERFLOW 2 + "tty-level buffer overflow", +}; + +#define CE_NTYPES 3 +#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum]) + +/* types. XXX - should be elsewhere */ +typedef u_int Port_t; /* hardware port */ +typedef int Bool_t; /* promoted boolean */ +typedef u_char bool_t; /* boolean */ + +/* com device structure */ +struct com_s { + u_char state; /* miscellaneous flag bits */ + u_char cfcr_image; /* copy of value written to CFCR */ + bool_t hasfifo; /* nonzero for 16550 UARTs */ + u_char mcr_image; /* copy of value written to MCR */ + bool_t softDCD; /* nonzero for faked carrier detect */ +#ifdef COM_BIDIR + bool_t bidir; /* is this unit bidirectional? */ + bool_t active; /* is the port active _at all_? */ + bool_t active_in; /* is the incoming port in use? */ + bool_t active_out; /* is the outgoing port in use? */ +#endif /* COM_BIDIR */ +#ifdef COM_MULTIPORT + bool_t multiport; /* is this unit part of a multiport device? */ +#endif /* COM_MULTIPORT */ + + /* + * The high level of the driver never reads status registers directly + * because there would be too many side effects to handle conveniently. + * Instead, it reads copies of the registers stored here by the + * interrupt handler. + */ + u_char last_modem_status; /* last MSR read by intr handler */ + u_char prev_modem_status; /* last MSR handled by high level */ + + u_char *ibuf; /* start of input buffer */ + u_char *ibufend; /* end of input buffer */ + u_char *ihighwater; /* threshold in input buffer */ + u_char *iptr; /* next free spot in input buffer */ + + u_char *obufend; /* end of output buffer */ + int ocount; /* original count for current output */ + u_char *optr; /* next char to output */ + + Port_t data_port; /* i/o ports */ + Port_t int_id_port; + Port_t iobase; + Port_t modem_ctl_port; + Port_t line_status_port; + Port_t modem_status_port; + + struct tty *tp; /* cross reference */ + + u_long bytes_in; /* statistics */ + u_long bytes_out; + u_int delta_error_counts[CE_NTYPES]; + u_int error_counts[CE_NTYPES]; + + /* + * Ping-pong input buffers. The extra factor of 2 in the sizes is + * to allow for an error byte for each input byte. + */ +#define CE_INPUT_OFFSET RS_IBUFSIZE + u_char ibuf1[2 * RS_IBUFSIZE]; + u_char ibuf2[2 * RS_IBUFSIZE]; +}; + + +/* + * These functions in the com module ought to be declared (with a prototype) + * in a com-driver system header. The void ones may need to be int to match + * ancient devswitch declarations, but they don't actually return anything. + */ +#define Dev_t int /* promoted dev_t */ +struct consdev; + +int sioclose __P((Dev_t dev, int fflag, int devtype, + struct proc *p)); +void siointr __P((int unit)); +#ifdef COM_MULTIPORT +bool_t comintr1 __P((struct com_s *com)); +#endif /* COM_MULTIPORT */ +int sioioctl __P((Dev_t dev, int cmd, caddr_t data, + int fflag, struct proc *p)); +int siocngetc __P((Dev_t dev)); +void siocninit __P((struct consdev *cp)); +void siocnprobe __P((struct consdev *cp)); +void siocnputc __P((Dev_t dev, int c)); +int sioopen __P((Dev_t dev, int oflags, int devtype, + struct proc *p)); +/* + * sioopen gets compared to the d_open entry in struct cdevsw. d_open and + * other functions are declared in <sys/conf.h> with short types like dev_t + * in the prototype. Such declarations are broken because they vary with + * __P (significantly in theory - the compiler is allowed to push a short + * arg if it has seen the prototype; insignificantly in practice - gcc + * doesn't push short args and it would be slower on 386's to do so). + * + * Also, most of the device switch functions are still declared old-style + * so they take a Dev_t arg and shorten it to a dev_t. It would be simpler + * and faster if dev_t's were always promoted (to ints or whatever) as + * early as possible. + * + * Until <sys/conf.h> is fixed, we cast sioopen to the following `wrong' type + * when comparing it to the d_open entry just to avoid compiler warnings. + */ +typedef int (*bogus_open_t) __P((dev_t dev, int oflags, int devtype, + struct proc *p)); +int sioread __P((Dev_t dev, struct uio *uio, int ioflag)); +void siostop __P((struct tty *tp, int rw)); +int siowrite __P((Dev_t dev, struct uio *uio, int ioflag)); +void softsio0 __P((void)); +void softsio1 __P((void)); +void softsio2 __P((void)); +void softsio3 __P((void)); +void softsio4 __P((void)); +void softsio5 __P((void)); +void softsio6 __P((void)); +void softsio7 __P((void)); +void softsio8 __P((void)); + +static int sioattach __P((struct isa_device *dev)); +static void comflush __P((struct com_s *com)); +static void comhardclose __P((struct com_s *com)); +static void cominit __P((int unit, int rate)); +static int commctl __P((struct com_s *com, int bits, int how)); +static int comparam __P((struct tty *tp, struct termios *t)); +static int sioprobe __P((struct isa_device *dev)); +static void compoll __P((void)); +static int comstart __P((struct tty *tp)); +static void comwakeup __P((void)); + +/* table and macro for fast conversion from a unit number to its com struct */ +static struct com_s *p_com_addr[NSIO]; +#define com_addr(unit) (p_com_addr[unit]) + +static struct com_s com_structs[NSIO]; + +struct isa_driver siodriver = { + sioprobe, sioattach, "sio" +}; + +#ifdef COMCONSOLE +static int comconsole = COMCONSOLE; +#else +static int comconsole = -1; +#endif +static bool_t comconsinit; +static speed_t comdefaultrate = TTYDEF_SPEED; +static u_int com_events; /* input chars + weighted output completions */ +static int commajor; +struct tty sio_tty[NSIO]; +extern struct tty *constty; +extern u_int ipending; /* XXX */ +extern int tk_nin; /* XXX */ +extern int tk_rawcc; /* XXX */ + +#ifdef KGDB +#include "machine/remote-sl.h" + +extern int kgdb_dev; +extern int kgdb_rate; +extern int kgdb_debug_init; +#endif + +static struct speedtab comspeedtab[] = { + 0, 0, + 50, COMBRD(50), + 75, COMBRD(75), + 110, COMBRD(110), + 134, COMBRD(134), + 150, COMBRD(150), + 200, COMBRD(200), + 300, COMBRD(300), + 600, COMBRD(600), + 1200, COMBRD(1200), + 1800, COMBRD(1800), + 2400, COMBRD(2400), + 4800, COMBRD(4800), + 9600, COMBRD(9600), + 19200, COMBRD(19200), + 38400, COMBRD(38400), + 57600, COMBRD(57600), + 115200, COMBRD(115200), + -1, -1 +}; + +/* XXX - configure this list */ +static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, }; + +static int +sioprobe(dev) + struct isa_device *dev; +{ + static bool_t already_init; + Port_t *com_ptr; + Port_t iobase; + int result; + + if (!already_init) { + /* + * Turn off MCR_IENABLE for all likely serial ports. An unused + * port with its MCR_IENABLE gate open will inhibit interrupts + * from any used port that shares the interrupt vector. + */ + for (com_ptr = likely_com_ports; + com_ptr < &likely_com_ports[sizeof likely_com_ports + / sizeof likely_com_ports[0]]; + ++com_ptr) + outb(*com_ptr + com_mcr, 0); + already_init = TRUE; + } + iobase = dev->id_iobase; + result = 1; + + /* + * We don't want to get actual interrupts, just masked ones. + * Interrupts from this line should already be masked in the ICU, + * but mask them in the processor as well in case there are some + * (misconfigured) shared interrupts. + */ + disable_intr(); + + /* + * Enable output interrupts (only) and check the following: + * o the CFCR, IER and MCR in UART hold the values written to them + * (the values happen to be all distinct - this is good for + * avoiding false positive tests from bus echoes). + * o an output interrupt is generated and its vector is correct. + * o the interrupt goes away when the IIR in the UART is read. + */ + outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */ + outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */ + outb(iobase + com_ier, 0); /* ensure edge on next intr */ + outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */ + if ( inb(iobase + com_cfcr) != CFCR_8BITS + || inb(iobase + com_ier) != IER_ETXRDY + || inb(iobase + com_mcr) != MCR_IENABLE + || !isa_irq_pending(dev) + || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY + || isa_irq_pending(dev) + || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND) + result = 0; + + /* + * Turn off all device interrupts and check that they go off properly. + * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to + * the ICU input. Closing the gate would give a floating ICU input + * (unless there is another device driving at) and spurious interrupts. + * (On the system that this was first tested on, the input floats high + * and gives a (masked) interrupt as soon as the gate is closed.) + */ + outb(iobase + com_ier, 0); + outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */ + if ( inb(iobase + com_ier) != 0 + || isa_irq_pending(dev) + || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND) + result = 0; + + enable_intr(); + + return (result); +} + +static int /* XXX - should be void */ +sioattach(isdp) + struct isa_device *isdp; +{ + struct com_s *com; + static bool_t comwakeup_started = FALSE; + Port_t iobase; + int s; + u_char scr; + u_char scr1; + u_char scr2; + int unit; + + iobase = isdp->id_iobase; + unit = isdp->id_unit; + if (unit == comconsole) + DELAY(1000); /* XXX */ + s = spltty(); + + /* + * sioprobe() has initialized the device registers as follows: + * o cfcr = CFCR_8BITS. + * It is most important that CFCR_DLAB is off, so that the + * data port is not hidden when we enable interrupts. + * o ier = 0. + * Interrupts are only enabled when the line is open. + * o mcr = MCR_IENABLE. + * Keeping MCR_DTR and MCR_RTS off might stop the external + * device from sending before we are ready. + */ + + com = &com_structs[unit]; + com->cfcr_image = CFCR_8BITS; + com->mcr_image = MCR_IENABLE; +#if 0 + com->softDCD = TRUE; +#endif + com->iptr = com->ibuf = com->ibuf1; + com->ibufend = com->ibuf1 + RS_IBUFSIZE; + com->ihighwater = com->ibuf1 + RS_IHIGHWATER; + com->iobase = iobase; + com->data_port = iobase + com_data; + com->int_id_port = iobase + com_iir; + com->modem_ctl_port = iobase + com_mcr; + com->line_status_port = iobase + com_lsr; + com->modem_status_port = iobase + com_msr; + com->tp = &sio_tty[unit]; +#ifdef COM_BIDIR + /* + * if bidirectional ports possible, clear the bidir port info; + */ + com->bidir = FALSE; + com->active = FALSE; + com->active_in = com->active_out = FALSE; +#endif /* COM_BIDIR */ + + /* attempt to determine UART type */ + scr = inb(iobase + com_scr); + outb(iobase + com_scr, 0xa5); + scr1 = inb(iobase + com_scr); + outb(iobase + com_scr, 0x5a); + scr2 = inb(iobase + com_scr); + outb(iobase + com_scr, scr); + if (scr1 != 0xa5 || scr2 != 0x5a) + printf(" <8250>"); + else { + outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14); + DELAY(100); + switch (inb(iobase + com_iir) & IIR_FIFO_MASK) { + case FIFO_TRIGGER_1: + printf(" <16450>"); + break; + case FIFO_TRIGGER_4: + printf(" <16450?>"); + break; + case FIFO_TRIGGER_8: + printf(" <16550?>"); + break; + case FIFO_TRIGGER_14: + com->hasfifo = TRUE; + printf(" <16550A>"); + break; + } + outb(iobase + com_fifo, 0); + } +#ifdef COM_MULTIPORT + if (COM_ISMULTIPORT(isdp)) { + struct isa_device *masterdev; + + com->multiport = TRUE; + printf(" (multiport)"); + + /* set the master's common-interrupt-enable reg., + * as appropriate. YYY See your manual + */ + /* enable only common interrupt for port */ + outb(iobase + com_mcr, 0); + + masterdev = find_isadev(isa_devtab_tty, &siodriver, + COM_MPMASTER(isdp)); + outb(masterdev->id_iobase+com_scr, 0x80); + } + else + com->multiport = FALSE; +#endif /* COM_MULTIPORT */ + +#ifdef KGDB + if (kgdb_dev == makedev(commajor, unit)) { + if (comconsole == unit) + kgdb_dev = -1; /* can't debug over console port */ + else { + cominit(unit, kgdb_rate); + if (kgdb_debug_init) { + /* + * Print prefix of device name, + * let kgdb_connect print the rest. + */ + printf("com%d: ", unit); + kgdb_connect(1); + } + else + printf("com%d: kgdb enabled\n", unit); + } + } +#endif + + /* + * Need to reset baud rate, etc. of next print so reset comconsinit. + * Also make sure console is always "hardwired" + */ + if (unit == comconsole) { + comconsinit = FALSE; + com->softDCD = TRUE; + } + + com_addr(unit) = com; + + splx(s); + + if (!comwakeup_started) { + comwakeup(); + comwakeup_started = TRUE; + } + + return (1); +} + +/* ARGSUSED */ +int +sioopen(dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + struct com_s *com; + int error = 0; + Port_t iobase; + int s; + struct tty *tp; + int unit = UNIT(dev); +#ifdef COM_BIDIR + bool_t callout = CALLOUT(dev); +#endif /* COM_BIDIR */ + if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL) + return (ENXIO); +#ifdef COM_BIDIR + /* if it's a callout device, and bidir not possible on that dev, die */ + if (callout && !(com->bidir)) + return (ENXIO); +#endif /* COM_BIDIR */ + + tp = com->tp; + s = spltty(); + +#ifdef COM_BIDIR + +bidir_open_top: + /* if it's bidirectional, we've gotta deal with it... */ + if (com->bidir) { + if (callout) { + if (com->active_in) { + /* it's busy. die */ + splx(s); + return (EBUSY); + } else { + /* it's ours. lock it down, and set it up */ + com->active_out = TRUE; + com->softDCD = TRUE; + } + } else { + if (com->active_out) { + /* it's busy, outgoing. wait, if possible */ + if (flag & O_NONBLOCK) { + /* can't wait; bail */ + splx(s); + return (EBUSY); + } else { + /* wait for it... */ + error = tsleep(&com->active_out, + TTIPRI|PCATCH, + "comoth", + 0); + /* if there was an error, take off. */ + if (error != 0) { + splx(s); + return (error); + } + /* else take it from the top */ + goto bidir_open_top; + } + } else if (com->last_modem_status & MSR_DCD) { + /* there's a carrier on the line; we win */ + com->active_in = TRUE; + com->softDCD = FALSE; + } else { + /* there is no carrier on the line */ + if (flag & O_NONBLOCK) { + /* can't wait; let it open */ + com->active_in = TRUE; + com->softDCD = FALSE; + } else { + /* put DTR & RTS up */ + /* NOTE: cgd'sdriver used the ier register + * to enable/disable interrupts. This one + * uses both ier and IENABLE in the mcr. + */ + (void) commctl(com, MCR_DTR | MCR_RTS, DMSET); + outb(com->iobase + com_ier, IER_EMSC); + /* wait for it... */ + error = tsleep(&com->active_in, + TTIPRI|PCATCH, + "comdcd", + 0); + + /* if not active, turn DTR & RTS off */ + if (!com->active) + (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC); + + /* if there was an error, take off. */ + if (error != 0) { + splx(s); + return (error); + } + /* else take it from the top */ + goto bidir_open_top; + } + } + } + } + + com->active = TRUE; +#endif /* COM_BIDIR */ + + tp->t_oproc = comstart; + tp->t_param = comparam; + tp->t_dev = dev; + if (!(tp->t_state & TS_ISOPEN)) { + tp->t_state |= TS_WOPEN; + ttychars(tp); + if (tp->t_ispeed == 0) { + /* + * We no longer use the flags from <sys/ttydefaults.h> + * since those are only relevant for logins. It's + * important to have echo off initially so that the + * line doesn't start blathering before the echo flag + * can be turned off. It's useful to have clocal on + * initially so that "stty changed-defaults </dev/comx" + * doesn't hang waiting for carrier. + */ + tp->t_iflag = 0; + tp->t_oflag = 0; + tp->t_cflag = CREAD | CS8 | CLOCAL; + tp->t_lflag = 0; + tp->t_ispeed = tp->t_ospeed = comdefaultrate; + } + (void) commctl(com, MCR_DTR | MCR_RTS, DMSET); + error = comparam(tp, &tp->t_termios); + if (error != 0) + goto out; + ttsetwater(tp); + iobase = com->iobase; + disable_intr(); + if (com->hasfifo) + /* (re)enable and drain FIFO */ + outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14 + | FIFO_RCV_RST | FIFO_XMT_RST); + (void) inb(com->line_status_port); + (void) inb(com->data_port); + com->last_modem_status = + com->prev_modem_status = inb(com->modem_status_port); + outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS + | IER_EMSC); + enable_intr(); + if (com->softDCD || com->prev_modem_status & MSR_DCD) + tp->t_state |= TS_CARR_ON; + } + else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { + splx(s); + return (EBUSY); + } + while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) +#ifdef COM_BIDIR + /* We went through a lot of trouble to open it, + * but it's certain we have a carrier now, so + * don't spend any time on it now. + */ + && !(com->bidir) +#endif /* COM_BIDIR */ + && !(tp->t_state & TS_CARR_ON)) { + tp->t_state |= TS_WOPEN; + error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, + ttopen, 0); + if (error != 0) + break; + } +out: + splx(s); + if (error == 0) + error = (*linesw[tp->t_line].l_open)(dev, tp); + +#ifdef COM_BIDIR + /* wakeup sleepers */ + wakeup((caddr_t) &com->active_in); +#endif /* COM_BIDIR */ + + /* + * XXX - the next step was once not done, so interrupts, DTR and RTS + * remainded hot if the process was killed while it was sleeping + * waiting for carrier. Now there is the opposite problem. If several + * processes are sleeping waiting for carrier on the same line and one + * is killed, interrupts are turned off so the other processes will + * never see the carrier rise. + */ + if (error != 0 && !(tp->t_state & TS_ISOPEN)) +{ + comhardclose(com); +} + tp->t_state &= ~TS_WOPEN; + + return (error); +} + +/*ARGSUSED*/ +int +sioclose(dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + struct com_s *com; + struct tty *tp; + + com = com_addr(UNIT(dev)); + tp = com->tp; + (*linesw[tp->t_line].l_close)(tp, flag); + comhardclose(com); + ttyclose(tp); + return (0); +} + +void +comhardclose(com) + struct com_s *com; +{ + Port_t iobase; + int s; + struct tty *tp; + + s = spltty(); + iobase = com->iobase; + outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); +#ifdef KGDB + /* do not disable interrupts if debugging */ + if (kgdb_dev != makedev(commajor, com - &com_structs[0])) +#endif + outb(iobase + com_ier, 0); + tp = com->tp; + if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN + || !(tp->t_state & TS_ISOPEN)) + (void) commctl(com, 0, DMSET); +#ifdef COM_BIDIR + com->active = com->active_in = com->active_out = FALSE; + com->softDCD = FALSE; + + /* wakeup sleepers who are waiting for out to finish */ + wakeup((caddr_t) &com->active_out); +#endif /* COM_BIDIR */ + + splx(s); +} + +int +sioread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct tty *tp = com_addr(UNIT(dev))->tp; + + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +int +siowrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + int unit = UNIT(dev); + struct tty *tp = com_addr(unit)->tp; + + /* + * (XXX) We disallow virtual consoles if the physical console is + * a serial port. This is in case there is a display attached that + * is not the console. In that situation we don't need/want the X + * server taking over the console. + */ + if (constty && unit == comconsole) + constty = NULL; + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +void +siointr(unit) + int unit; +{ + struct com_s *com; +#ifndef COM_MULTIPORT + u_char line_status; + u_char modem_status; + u_char *ioptr; + u_char recv_data; + + com = com_addr(unit); +#else /* COM_MULTIPORT */ + int i; + bool_t donesomething; + + do { + donesomething = FALSE; + for(i=0;i<NSIO;i++) { + com=com_addr(i); + if(com != NULL) { + /* XXX When siointr is called + * to start output, maybe + * it should be changed to a + * call to comintr1. Doesn't + * seem a good idea: interrupts + * are disabled all the time. + */ +enable_intr(); +disable_intr(); + donesomething = comintr1(com); + } + } + } while (donesomething); + return; +} + +bool_t +comintr1(struct com_s *com) +{ + u_char line_status; + u_char modem_status; + u_char *ioptr; + u_char recv_data; + bool_t donesomething; + + donesomething = FALSE; +#endif /* COM_MULTIPORT */ + + while (TRUE) { + line_status = inb(com->line_status_port); + + /* input event? (check first to help avoid overruns) */ + while (line_status & LSR_RCV_MASK) { + /* break/unnattached error bits or real input? */ +#ifdef COM_MULTIPORT + donesomething = TRUE; +#endif /* COM_MULTIPORT */ + if (!(line_status & LSR_RXRDY)) + recv_data = 0; + else + recv_data = inb(com->data_port); + ++com->bytes_in; +#ifdef KGDB + /* trap into kgdb? (XXX - needs testing and optim) */ + if (recv_data == FRAME_END + && !(com->tp->t_state & TS_ISOPEN) + && kgdb_dev == makedev(commajor, unit)) { + kgdb_connect(0); + continue; + } +#endif /* KGDB */ + ioptr = com->iptr; + if (ioptr >= com->ibufend) + CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW); + else { + ++com_events; + ioptr[0] = recv_data; + ioptr[CE_INPUT_OFFSET] = line_status; + com->iptr = ++ioptr; + if (ioptr == com->ihighwater + && com->state & CS_RTS_IFLOW) + outb(com->modem_ctl_port, + com->mcr_image &= ~MCR_RTS); + } + + /* + * "& 0x7F" is to avoid the gcc-1.40 generating a slow + * jump from the top of the loop to here + */ + line_status = inb(com->line_status_port) & 0x7F; + } + + /* modem status change? (always check before doing output) */ + modem_status = inb(com->modem_status_port); + if (modem_status != com->last_modem_status) { + /* + * Schedule high level to handle DCD changes. Note + * that we don't use the delta bits anywhere. Some + * UARTs mess them up, and it's easy to remember the + * previous bits and calculate the delta. + */ +#ifdef COM_MULTIPORT + donesomething = TRUE; +#endif /* COM_MULTIPORT */ + com->last_modem_status = modem_status; + if (!(com->state & CS_CHECKMSR)) { + com_events += LOTS_OF_EVENTS; + com->state |= CS_CHECKMSR; + schedsoftcom(); + } + + /* handle CTS change immediately for crisp flow ctl */ + if (com->state & CS_CTS_OFLOW) { + if (modem_status & MSR_CTS) + com->state |= CS_ODEVREADY; + else + com->state &= ~CS_ODEVREADY; + } + } + + /* output queued and everything ready? */ + if (line_status & LSR_TXRDY + && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) { +#ifdef COM_MULTIPORT + donesomething = TRUE; +#endif /* COM_MULTIPORT */ + ioptr = com->optr; + outb(com->data_port, *ioptr); + ++com->bytes_out; + com->optr = ++ioptr; + if (ioptr >= com->obufend) { + /* output just completed */ + com_events += LOTS_OF_EVENTS; + com->state ^= (CS_ODONE | CS_BUSY); + schedsoftcom(); /* handle at high level ASAP */ + } + } + + /* finished? */ + if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND) +#ifdef COM_MULTIPORT + return (donesomething); +#else + return; +#endif /* COM_MULTIPORT */ + } +} + +int +sioioctl(dev, cmd, data, flag, p) + dev_t dev; + int cmd; + caddr_t data; + int flag; + struct proc *p; +{ + struct com_s *com; + int error; + Port_t iobase; + int s; + struct tty *tp; + + com = com_addr(UNIT(dev)); + tp = com->tp; + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); + if (error >= 0) + return (error); + error = ttioctl(tp, cmd, data, flag); + if (error >= 0) + return (error); + + iobase = com->iobase; + s = spltty(); + switch (cmd) { + case TIOCSBRK: + outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK); + break; + case TIOCCBRK: + outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); + break; + case TIOCSDTR: + (void) commctl(com, MCR_DTR | MCR_RTS, DMBIS); + break; + case TIOCCDTR: + (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC); + break; + case TIOCMSET: + (void) commctl(com, *(int *)data, DMSET); + break; + case TIOCMBIS: + (void) commctl(com, *(int *)data, DMBIS); + break; + case TIOCMBIC: + (void) commctl(com, *(int *)data, DMBIC); + break; + case TIOCMGET: + *(int *)data = commctl(com, 0, DMGET); + break; +#ifdef COM_BIDIR + case TIOCMSBIDIR: + /* must be root to set bidir. capability */ + if (p->p_ucred->cr_uid != 0) + return(EPERM); + + /* if it's the console, can't do it */ + if (UNIT(dev) == comconsole) + return(ENOTTY); + + /* can't do the next, for obvious reasons... + * but there are problems to be looked at... + */ + + /* if the port is active, don't do it */ + /* if (com->active) + return(EBUSY); */ + + com->bidir = *(int *)data; + break; + case TIOCMGBIDIR: + *(int *)data = com->bidir; + break; +#endif /* COM_BIDIR */ + default: + splx(s); + return (ENOTTY); + } + splx(s); + return (0); +} + +/* cancel pending output */ +static void +comflush(com) + struct com_s *com; +{ + struct ringb *rbp; + + disable_intr(); + if (com->state & CS_ODONE) + com_events -= LOTS_OF_EVENTS; + com->state &= ~(CS_ODONE | CS_BUSY); + enable_intr(); + rbp = &com->tp->t_out; + rbp->rb_hd += com->ocount; + rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd); + com->ocount = 0; + com->tp->t_state &= ~TS_BUSY; +} + +static void +compoll() +{ + static bool_t awake = FALSE; + struct com_s *com; + int s; + int unit; + + if (com_events == 0) + return; + disable_intr(); + if (awake) { + enable_intr(); + return; + } + awake = TRUE; + enable_intr(); + s = spltty(); +repeat: + for (unit = 0; unit < NSIO; ++unit) { + u_char *buf; + u_char *ibuf; + int incc; + struct tty *tp; + + com = com_addr(unit); + if (com == NULL) + continue; + tp = com->tp; + + /* switch the role of the low-level input buffers */ + if (com->iptr == (ibuf = com->ibuf)) + incc = 0; + else { + buf = ibuf; + disable_intr(); + incc = com->iptr - buf; + com_events -= incc; + if (ibuf == com->ibuf1) + ibuf = com->ibuf2; + else + ibuf = com->ibuf1; + com->ibufend = ibuf + RS_IBUFSIZE; + com->ihighwater = ibuf + RS_IHIGHWATER; + com->iptr = ibuf; + + /* + * There is now room for another low-level buffer full + * of input, so enable RTS if it is now disabled and + * there is room in the high-level buffer. + */ + if (!(com->mcr_image & MCR_RTS) + && !(tp->t_state & TS_RTSBLOCK)) + outb(com->modem_ctl_port, + com->mcr_image |= MCR_RTS); + enable_intr(); + com->ibuf = ibuf; + } + + if (com->state & CS_CHECKMSR) { + u_char delta_modem_status; + + disable_intr(); + delta_modem_status = com->last_modem_status + ^ com->prev_modem_status; + com->prev_modem_status = com->last_modem_status; + com_events -= LOTS_OF_EVENTS; + com->state &= ~CS_CHECKMSR; + enable_intr(); + if (delta_modem_status & MSR_DCD && + unit != comconsole) { +#ifdef COM_BIDIR + if (com->prev_modem_status & MSR_DCD) { + (*linesw[tp->t_line].l_modem)(tp, 1); + com->softDCD = FALSE; + wakeup((caddr_t) &com->active_in); + } +#else + if (com->prev_modem_status & MSR_DCD) + (*linesw[tp->t_line].l_modem)(tp, 1); +#endif /* COM_BIDIR */ + else if ((*linesw[tp->t_line].l_modem)(tp, 0) + == 0) { + disable_intr(); + outb(com->modem_ctl_port, + com->mcr_image + &= ~(MCR_DTR | MCR_RTS)); + enable_intr(); + } + } + } + + /* XXX */ + if (TRUE) { + u_int delta; + u_int delta_error_counts[CE_NTYPES]; + int errnum; + u_long total; + + disable_intr(); + bcopy(com->delta_error_counts, delta_error_counts, + sizeof delta_error_counts); + bzero(com->delta_error_counts, + sizeof delta_error_counts); + enable_intr(); + for (errnum = 0; errnum < CE_NTYPES; ++errnum) { + delta = delta_error_counts[errnum]; + if (delta != 0) { + total = + com->error_counts[errnum] += delta; + log(LOG_WARNING, + "com%d: %u more %s%s (total %lu)\n", + unit, delta, error_desc[errnum], + delta == 1 ? "" : "s", total); + } + } + } + if (com->state & CS_ODONE) { + comflush(com); + /* XXX - why isn't the table used for t_line == 0? */ + if (tp->t_line != 0) + (*linesw[tp->t_line].l_start)(tp); + else + comstart(tp); + } + if (incc <= 0 || !(tp->t_state & TS_ISOPEN)) + continue; + if (com->state & CS_RTS_IFLOW + && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER + && !(tp->t_state & TS_RTSBLOCK) + /* + * XXX - need RTS flow control for all line disciplines. + * Only have it in standard one now. + */ + && linesw[tp->t_line].l_rint == ttyinput) { + tp->t_state |= TS_RTSBLOCK; + ttstart(tp); + } + /* + * Avoid the grotesquely inefficient lineswitch routine + * (ttyinput) in "raw" mode. It usually takes about 450 + * instructions (that's without canonical processing or echo!). + * slinput is reasonably fast (usually 40 instructions plus + * call overhead). + */ + if (!(tp->t_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP + | IXOFF | IXON)) + && !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG + | PENDIN)) + && !(tp->t_state & (TS_CNTTB | TS_LNCH)) + && linesw[tp->t_line].l_rint == ttyinput) { + tk_nin += incc; + tk_rawcc += incc; + tp->t_rawcc += incc; + com->delta_error_counts[CE_TTY_BUF_OVERFLOW] + += incc - rb_write(&tp->t_raw, (char *) buf, + incc); + ttwakeup(tp); + if (tp->t_state & TS_TTSTOP + && (tp->t_iflag & IXANY + || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { + tp->t_state &= ~TS_TTSTOP; + tp->t_lflag &= ~FLUSHO; + ttstart(tp); + } + } + else { + do { + u_char line_status; + int recv_data; + + line_status = (u_char) buf[CE_INPUT_OFFSET]; + recv_data = (u_char) *buf++; + if (line_status + & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) { + if (line_status & LSR_BI) + recv_data |= TTY_BI; + if (line_status & LSR_FE) + recv_data |= TTY_FE; + if (line_status & LSR_OE) + recv_data |= TTY_OE; + if (line_status & LSR_PE) + recv_data |= TTY_PE; + } + (*linesw[tp->t_line].l_rint)(recv_data, tp); + } while (--incc > 0); + } + if (com_events == 0) + break; + } + if (com_events >= LOTS_OF_EVENTS) + goto repeat; + splx(s); + awake = FALSE; +} + +static int +comparam(tp, t) + struct tty *tp; + struct termios *t; +{ + u_int cfcr; + int cflag; + struct com_s *com; + int divisor; + int error; + Port_t iobase; + int s; + int unit; + + /* check requested parameters */ + divisor = ttspeedtab(t->c_ospeed, comspeedtab); + if (divisor < 0 || t->c_ispeed != 0 && t->c_ispeed != t->c_ospeed) + return (EINVAL); + + /* parameters are OK, convert them to the com struct and the device */ + unit = UNIT(tp->t_dev); + com = com_addr(unit); + iobase = com->iobase; + s = spltty(); + if (divisor == 0) { + (void) commctl(com, 0, DMSET); /* hang up line */ + splx(s); + return (0); + } + cflag = t->c_cflag; + switch (cflag & CSIZE) { + case CS5: + cfcr = CFCR_5BITS; + break; + case CS6: + cfcr = CFCR_6BITS; + break; + case CS7: + cfcr = CFCR_7BITS; + break; + default: + cfcr = CFCR_8BITS; + break; + } + if (cflag & PARENB) { + cfcr |= CFCR_PENAB; + if (!(cflag & PARODD)) + cfcr |= CFCR_PEVEN; + } + if (cflag & CSTOPB) + cfcr |= CFCR_STOPB; + + /* + * Some UARTs lock up if the divisor latch registers are selected + * while the UART is doing output (they refuse to transmit anything + * more until given a hard reset). Fix this by stopping filling + * the device buffers and waiting for them to drain. Reading the + * line status port outside of siointr() might lose some receiver + * error bits, but that is acceptable here. + */ + disable_intr(); + com->state &= ~CS_TTGO; + enable_intr(); + while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) + != (LSR_TSRE | LSR_TXRDY)) { + error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, + "comparam", 1); + if (error != 0 && error != EAGAIN) { + if (!(tp->t_state & TS_TTSTOP)) { + disable_intr(); + com->state |= CS_TTGO; + enable_intr(); + } + splx(s); + return (error); + } + } + + disable_intr(); /* very important while com_data is hidden */ + outb(iobase + com_cfcr, cfcr | CFCR_DLAB); + outb(iobase + com_dlbl, divisor & 0xFF); + outb(iobase + com_dlbh, (u_int) divisor >> 8); + outb(iobase + com_cfcr, com->cfcr_image = cfcr); + if (!(tp->t_state & TS_TTSTOP)) + com->state |= CS_TTGO; + if (cflag & CRTS_IFLOW) + com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */ + else + com->state &= ~CS_RTS_IFLOW; + + /* + * Set up state to handle output flow control. + * XXX - worth handling MDMBUF (DCD) flow control at the lowest level? + * Now has 16+ msec latency, while CTS flow has 50- usec latency. + * Note that DCD flow control stupidly uses the same state flag + * (TS_TTSTOP) as XON/XOFF flow control. + */ + com->state &= ~CS_CTS_OFLOW; + com->state |= CS_ODEVREADY; + if (cflag & CCTS_OFLOW) { + com->state |= CS_CTS_OFLOW; + if (!(com->prev_modem_status & MSR_CTS)) + com->state &= ~CS_ODEVREADY; + } + + enable_intr(); + siointr(unit); /* recover from fiddling with CS_TTGO */ + splx(s); + return (0); +} + +static int /* XXX - should be void */ +comstart(tp) + struct tty *tp; +{ + struct com_s *com; + int s; + int unit; + + unit = UNIT(tp->t_dev); + com = com_addr(unit); + s = spltty(); + disable_intr(); + if (tp->t_state & TS_TTSTOP) + com->state &= ~CS_TTGO; + else + com->state |= CS_TTGO; + if (tp->t_state & TS_RTSBLOCK) { + if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW) + outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); + } + else { + if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater) + outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); + } + enable_intr(); + if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) + goto out; + if (RB_LEN(&tp->t_out) <= tp->t_lowat) { + if (tp->t_state & TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t)&tp->t_out); + } + if (tp->t_wsel) { + selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); + tp->t_wsel = 0; + tp->t_state &= ~TS_WCOLL; + } + } + if (com->ocount != 0) { + disable_intr(); + siointr(unit); + enable_intr(); + } + else if (RB_LEN(&tp->t_out) != 0) { + tp->t_state |= TS_BUSY; + com->ocount = RB_CONTIGGET(&tp->t_out); + disable_intr(); + com->obufend = (com->optr = (u_char *) tp->t_out.rb_hd) + + com->ocount; + com->state |= CS_BUSY; + siointr(unit); /* fake interrupt to start output */ + enable_intr(); + } +out: + splx(s); + return (1); +} + +void +siostop(tp, rw) + struct tty *tp; + int rw; +{ + struct com_s *com; + + com = com_addr(UNIT(tp->t_dev)); + if (rw & FWRITE) + comflush(com); + disable_intr(); + if (tp->t_state & TS_TTSTOP) + com->state &= ~CS_TTGO; + else + com->state |= CS_TTGO; + enable_intr(); +} + +static int +commctl(com, bits, how) + struct com_s *com; + int bits; + int how; +{ + disable_intr(); + switch (how) { + case DMSET: +#ifdef COM_MULTIPORT + /* YYY maybe your card doesn't want IENABLE to be reset? */ + if(com->multiport) + outb(com->modem_ctl_port, + com->mcr_image = bits); + else +#endif /* COM_MULTIPORT */ + outb(com->modem_ctl_port, + com->mcr_image = bits | MCR_IENABLE); + break; + case DMBIS: + outb(com->modem_ctl_port, com->mcr_image |= bits); + break; + case DMBIC: +#ifdef COM_MULTIPORT + /* YYY maybe your card doesn't want IENABLE to be reset? */ + if(com->multiport) + outb(com->modem_ctl_port, + com->mcr_image &= ~(bits)); + else +#endif /* COM_MULTIPORT */ + outb(com->modem_ctl_port, + com->mcr_image &= ~(bits & ~MCR_IENABLE)); + break; + case DMGET: + bits = com->prev_modem_status; + break; + } + enable_intr(); + return (bits); +} + +static void +comwakeup() +{ + struct com_s *com; + int unit; + + timeout((timeout_func_t) comwakeup, (caddr_t) NULL, 1); + if (com_events != 0) + /* schedule compoll() to run when the cpl allows */ + schedsoftcom(); + + /* recover from lost output interrupts */ + for (unit = 0; unit < NSIO; ++unit) { + com = com_addr(unit); + if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) { + disable_intr(); + siointr(unit); + enable_intr(); + } + } +} + +void +softsio0() { compoll(); } + +void +softsio1() { compoll(); } + +void +softsio2() { compoll(); } + +void +softsio3() { compoll(); } + +void +softsio4() { compoll(); } + +void +softsio5() { compoll(); } + +void +softsio6() { compoll(); } + +void +softsio7() { compoll(); } + +void +softsio8() { compoll(); } + +/* + * Following are all routines needed for COM to act as console + * XXX - not tested in this version + * XXX - check that the corresponding serial interrupts are never enabled + */ +#include "i386/i386/cons.h" + +void +siocnprobe(cp) + struct consdev *cp; +{ + int unit; + + /* locate the major number */ + for (commajor = 0; commajor < nchrdev; commajor++) + if (cdevsw[commajor].d_open == (bogus_open_t) sioopen) + break; + + /* XXX: ick */ + unit = CONUNIT; + com_addr(unit) = &com_structs[unit]; + com_addr(unit)->iobase = CONADDR; + + /* make sure hardware exists? XXX */ + + /* initialize required fields */ + cp->cn_dev = makedev(commajor, unit); + cp->cn_tp = &sio_tty[unit]; +#ifdef COMCONSOLE + cp->cn_pri = CN_REMOTE; /* Force a serial port console */ +#else + cp->cn_pri = CN_NORMAL; +#endif +} + +void +siocninit(cp) + struct consdev *cp; +{ + int unit; + + unit = UNIT(cp->cn_dev); + cominit(unit, comdefaultrate); + comconsole = unit; + comconsinit = TRUE; +} + +static void +cominit(unit, rate) + int unit; + int rate; +{ + Port_t iobase; + int s; + + iobase = com_addr(unit)->iobase; + s = splhigh(); + outb(iobase + com_cfcr, CFCR_DLAB); + rate = ttspeedtab(comdefaultrate, comspeedtab); + outb(iobase + com_data, rate & 0xFF); + outb(iobase + com_ier, rate >> 8); + outb(iobase + com_cfcr, CFCR_8BITS); + + /* + * XXX - fishy to enable interrupts and then poll. + * It shouldn't be necessary to ready the iir. + */ + outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); + outb(iobase + com_fifo, + FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); + (void) inb(iobase + com_iir); + splx(s); +} + +int +siocngetc(dev) + dev_t dev; +{ + int c; + Port_t iobase; + int s; + + iobase = com_addr(UNIT(dev))->iobase; + s = splhigh(); + while (!(inb(iobase + com_lsr) & LSR_RXRDY)) + ; + c = inb(iobase + com_data); + (void) inb(iobase + com_iir); + splx(s); + return (c); +} + +void +siocnputc(dev, c) + dev_t dev; + int c; +{ + Port_t iobase; + int s; + int timo; + + iobase = com_addr(UNIT(dev))->iobase; + s = splhigh(); +#ifdef KGDB + if (dev != kgdb_dev) +#endif + if (!comconsinit) { + (void) cominit(UNIT(dev), comdefaultrate); + comconsinit = TRUE; + } + /* wait for any pending transmission to finish */ + timo = 50000; + while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo) + ; + outb(iobase + com_data, c); + /* wait for this transmission to complete */ + timo = 1500000; + while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo) + ; + /* clear any interrupts generated by this transmission */ + (void) inb(iobase + com_iir); + splx(s); +} + +/* + * 10 Feb 93 Jordan K. Hubbard Added select code + * 27 May 93 Rodney W. Grimes Stole the select code from com.c.pl5 + */ + +int +sioselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; +{ + register struct tty *tp = &sio_tty[UNIT(dev)]; + int nread; + int s = spltty(); + struct proc *selp; + + switch (rw) { + + case FREAD: + nread = ttnread(tp); + if (nread > 0 || + ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) + goto win; + if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_RCOLL; + else + tp->t_rsel = p->p_pid; + break; + + case FWRITE: + if (RB_LEN(&tp->t_out) <= tp->t_lowat) + goto win; + if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_WCOLL; + else + tp->t_wsel = p->p_pid; + break; + } + splx(s); + return (0); + win: + splx(s); + return (1); +} + +#endif /* NSIO > 0 */ diff --git a/sys/i386/isa/sioreg.h b/sys/i386/isa/sioreg.h new file mode 100644 index 000000000000..2a626832e87c --- /dev/null +++ b/sys/i386/isa/sioreg.h @@ -0,0 +1,113 @@ +/*- + * 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. + * + * @(#)comreg.h 7.2 (Berkeley) 5/9/91 + */ + + +/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */ +#define COMBRD(x) (1843200 / (16*(x))) + +/* interrupt enable register */ +#define IER_ERXRDY 0x1 +#define IER_ETXRDY 0x2 +#define IER_ERLS 0x4 +#define IER_EMSC 0x8 + +/* interrupt identification register */ +#define IIR_IMASK 0xf +#define IIR_RXTOUT 0xc +#define IIR_RLS 0x6 +#define IIR_RXRDY 0x4 +#define IIR_TXRDY 0x2 +#define IIR_NOPEND 0x1 +#define IIR_MLSC 0x0 +#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */ + +/* fifo control register */ +#define FIFO_ENABLE 0x01 +#define FIFO_RCV_RST 0x02 +#define FIFO_XMT_RST 0x04 +#define FIFO_DMA_MODE 0x08 +#define FIFO_TRIGGER_1 0x00 +#define FIFO_TRIGGER_4 0x40 +#define FIFO_TRIGGER_8 0x80 +#define FIFO_TRIGGER_14 0xc0 + +/* character format control register */ +#define CFCR_DLAB 0x80 +#define CFCR_SBREAK 0x40 +#define CFCR_PZERO 0x30 +#define CFCR_PONE 0x20 +#define CFCR_PEVEN 0x10 +#define CFCR_PODD 0x00 +#define CFCR_PENAB 0x08 +#define CFCR_STOPB 0x04 +#define CFCR_8BITS 0x03 +#define CFCR_7BITS 0x02 +#define CFCR_6BITS 0x01 +#define CFCR_5BITS 0x00 + +/* modem control register */ +#define MCR_LOOPBACK 0x10 +#define MCR_IENABLE 0x08 +#define MCR_DRS 0x04 +#define MCR_RTS 0x02 +#define MCR_DTR 0x01 + +/* line status register */ +#define LSR_RCV_FIFO 0x80 +#define LSR_TSRE 0x40 +#define LSR_TXRDY 0x20 +#define LSR_BI 0x10 +#define LSR_FE 0x08 +#define LSR_PE 0x04 +#define LSR_OE 0x02 +#define LSR_RXRDY 0x01 +#define LSR_RCV_MASK 0x1f + +/* modem status register */ +#define MSR_DCD 0x80 +#define MSR_RI 0x40 +#define MSR_DSR 0x20 +#define MSR_CTS 0x10 +#define MSR_DDCD 0x08 +#define MSR_TERI 0x04 +#define MSR_DDSR 0x02 +#define MSR_DCTS 0x01 + +/* + * WARNING: Serial console is assumed to be at COM1 address + * and CONUNIT must be 0. + */ +#define CONADDR (0x3f8) +#define CONUNIT (0) diff --git a/sys/i386/isa/spkr.c b/sys/i386/isa/spkr.c new file mode 100644 index 000000000000..ffeec08fe5dd --- /dev/null +++ b/sys/i386/isa/spkr.c @@ -0,0 +1,520 @@ +/* + * spkr.c -- device driver for console speaker on 80386 + * + * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 + * modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su> + * 386bsd only clean version, all SYSV stuff removed + * use hz value from param.c + */ + +#include "speaker.h" + +#if NSPEAKER > 0 + +#include "param.h" +#include "kernel.h" +#include "errno.h" +#include "buf.h" +#include "uio.h" +#include "spkr.h" + +/**************** MACHINE DEPENDENT PART STARTS HERE ************************* + * + * This section defines a function tone() which causes a tone of given + * frequency and duration from the 80x86's console speaker. + * Another function endtone() is defined to force sound off, and there is + * also a rest() entry point to do pauses. + * + * Audible sound is generated using the Programmable Interval Timer (PIT) and + * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The + * PPI controls whether sound is passed through at all; the PIT's channel 2 is + * used to generate clicks (a square wave) of whatever frequency is desired. + */ + +/* + * PIT and PPI port addresses and control values + * + * Most of the magic is hidden in the TIMER_PREP value, which selects PIT + * channel 2, frequency LSB first, square-wave mode and binary encoding. + * The encoding is as follows: + * + * +----------+----------+---------------+-----+ + * | 1 0 | 1 1 | 0 1 1 | 0 | + * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD | + * +----------+----------+---------------+-----+ + * Counter Write Mode 3 Binary + * Channel 2 LSB first, (Square Wave) Encoding + * MSB second + */ +#define PPI 0x61 /* port of Programmable Peripheral Interface */ +#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ +#define PIT_CTRL 0x43 /* PIT control address */ +#define PIT_COUNT 0x42 /* PIT count address */ +#define PIT_MODE 0xB6 /* set timer mode for sound generation */ + +/* + * Magic numbers for timer control. + */ +#define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */ + +static int endtone() +/* turn off the speaker, ending current tone */ +{ + wakeup((caddr_t)endtone); + outb(PPI, inb(PPI) & ~PPI_SPKR); +} + +static void tone(hz, ticks) +/* emit tone of frequency hz for given number of ticks */ +unsigned int hz, ticks; +{ + unsigned int divisor = TIMER_CLK / hz; + int sps; + +#ifdef DEBUG + printf("tone: hz=%d ticks=%d\n", hz, ticks); +#endif /* DEBUG */ + + /* set timer to generate clicks at given frequency in Hertz */ + sps = spltty(); + outb(PIT_CTRL, PIT_MODE); /* prepare timer */ + outb(PIT_COUNT, (unsigned char) divisor); /* send lo byte */ + outb(PIT_COUNT, (divisor >> 8)); /* send hi byte */ + splx(sps); + + /* turn the speaker on */ + outb(PPI, inb(PPI) | PPI_SPKR); + + /* + * Set timeout to endtone function, then give up the timeslice. + * This is so other processes can execute while the tone is being + * emitted. + */ + timeout((caddr_t)endtone, (caddr_t)NULL, ticks); + sleep((caddr_t)endtone, PZERO - 1); +} + +static int endrest() +/* end a rest */ +{ + wakeup((caddr_t)endrest); +} + +static void rest(ticks) +/* rest for given number of ticks */ +int ticks; +{ + /* + * Set timeout to endrest function, then give up the timeslice. + * This is so other processes can execute while the rest is being + * waited out. + */ +#ifdef DEBUG + printf("rest: %d\n", ticks); +#endif /* DEBUG */ + timeout((caddr_t)endrest, (caddr_t)NULL, ticks); + sleep((caddr_t)endrest, PZERO - 1); +} + +/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** + * + * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; + * M[LNS] are missing and the ~ synonym and octave-tracking facility is added. + * Requires tone(), rest(), and endtone(). String play is not interruptible + * except possibly at physical block boundaries. + */ + +typedef int bool; +#define TRUE 1 +#define FALSE 0 + +#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) +#define isdigit(c) (((c) >= '0') && ((c) <= '9')) +#define dtoi(c) ((c) - '0') + +static int octave; /* currently selected octave */ +static int whole; /* whole-note time at current tempo, in ticks */ +static int value; /* whole divisor for note time, quarter note = 1 */ +static int fill; /* controls spacing of notes */ +static bool octtrack; /* octave-tracking on? */ +static bool octprefix; /* override current octave-tracking state? */ + +/* + * Magic number avoidance... + */ +#define SECS_PER_MIN 60 /* seconds per minute */ +#define WHOLE_NOTE 4 /* quarter notes per whole note */ +#define MIN_VALUE 64 /* the most we can divide a note by */ +#define DFLT_VALUE 4 /* default value (quarter-note) */ +#define FILLTIME 8 /* for articulation, break note in parts */ +#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ +#define NORMAL 7 /* 7/8ths of note interval is filled */ +#define LEGATO 8 /* all of note interval is filled */ +#define DFLT_OCTAVE 4 /* default octave */ +#define MIN_TEMPO 32 /* minimum tempo */ +#define DFLT_TEMPO 120 /* default tempo */ +#define MAX_TEMPO 255 /* max tempo */ +#define NUM_MULT 3 /* numerator of dot multiplier */ +#define DENOM_MULT 2 /* denominator of dot multiplier */ + +/* letter to half-tone: A B C D E F G */ +static int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; + +/* + * This is the American Standard A440 Equal-Tempered scale with frequencies + * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... + * our octave 0 is standard octave 2. + */ +#define OCTAVE_NOTES 12 /* semitones per octave */ +static int pitchtab[] = +{ +/* C C# D D# E F F# G G# A A# B*/ +/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, +/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, +/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, +/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, +/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, +/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, +/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, +}; + +static void playinit() +{ + octave = DFLT_OCTAVE; + whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; + fill = NORMAL; + value = DFLT_VALUE; + octtrack = FALSE; + octprefix = TRUE; /* act as though there was an initial O(n) */ +} + +static void playtone(pitch, value, sustain) +/* play tone of proper duration for current rhythm signature */ +int pitch, value, sustain; +{ + register int sound, silence, snum = 1, sdenom = 1; + + /* this weirdness avoids floating-point arithmetic */ + for (; sustain; sustain--) + { + snum *= NUM_MULT; + sdenom *= DENOM_MULT; + } + + if (pitch == -1) + rest(whole * snum / (value * sdenom)); + else + { + sound = (whole * snum) / (value * sdenom) + - (whole * (FILLTIME - fill)) / (value * FILLTIME); + silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); + +#ifdef DEBUG + printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", + pitch, sound, silence); +#endif /* DEBUG */ + + tone(pitchtab[pitch], sound); + if (fill != LEGATO) + rest(silence); + } +} + +static int abs(n) +int n; +{ + if (n < 0) + return(-n); + else + return(n); +} + +static void playstring(cp, slen) +/* interpret and play an item from a notation string */ +char *cp; +size_t slen; +{ + int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; + +#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ + {v = v * 10 + (*++cp - '0'); slen--;} + for (; slen--; cp++) + { + int sustain, timeval, tempo; + register char c = toupper(*cp); + +#ifdef DEBUG + printf("playstring: %c (%x)\n", c, c); +#endif /* DEBUG */ + + switch (c) + { + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': + + /* compute pitch */ + pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; + + /* this may be followed by an accidental sign */ + if (cp[1] == '#' || cp[1] == '+') + { + ++pitch; + ++cp; + slen--; + } + else if (cp[1] == '-') + { + --pitch; + ++cp; + slen--; + } + + /* + * If octave-tracking mode is on, and there has been no octave- + * setting prefix, find the version of the current letter note + * closest to the last regardless of octave. + */ + if (octtrack && !octprefix) + { + if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) + { + ++octave; + pitch += OCTAVE_NOTES; + } + + if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) + { + --octave; + pitch -= OCTAVE_NOTES; + } + } + octprefix = FALSE; + lastpitch = pitch; + + /* ...which may in turn be followed by an override time value */ + GETNUM(cp, timeval); + if (timeval <= 0 || timeval > MIN_VALUE) + timeval = value; + + /* ...and/or sustain dots */ + for (sustain = 0; cp[1] == '.'; cp++) + { + slen--; + sustain++; + } + + /* time to emit the actual tone */ + playtone(pitch, timeval, sustain); + break; + + case 'O': + if (cp[1] == 'N' || cp[1] == 'n') + { + octprefix = octtrack = FALSE; + ++cp; + slen--; + } + else if (cp[1] == 'L' || cp[1] == 'l') + { + octtrack = TRUE; + ++cp; + slen--; + } + else + { + GETNUM(cp, octave); + if (octave >= sizeof(pitchtab) / OCTAVE_NOTES) + octave = DFLT_OCTAVE; + octprefix = TRUE; + } + break; + + case '>': + if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1) + octave++; + octprefix = TRUE; + break; + + case '<': + if (octave > 0) + octave--; + octprefix = TRUE; + break; + + case 'N': + GETNUM(cp, pitch); + for (sustain = 0; cp[1] == '.'; cp++) + { + slen--; + sustain++; + } + playtone(pitch - 1, value, sustain); + break; + + case 'L': + GETNUM(cp, value); + if (value <= 0 || value > MIN_VALUE) + value = DFLT_VALUE; + break; + + case 'P': + case '~': + /* this may be followed by an override time value */ + GETNUM(cp, timeval); + if (timeval <= 0 || timeval > MIN_VALUE) + timeval = value; + for (sustain = 0; cp[1] == '.'; cp++) + { + slen--; + sustain++; + } + playtone(-1, timeval, sustain); + break; + + case 'T': + GETNUM(cp, tempo); + if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) + tempo = DFLT_TEMPO; + whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo; + break; + + case 'M': + if (cp[1] == 'N' || cp[1] == 'n') + { + fill = NORMAL; + ++cp; + slen--; + } + else if (cp[1] == 'L' || cp[1] == 'l') + { + fill = LEGATO; + ++cp; + slen--; + } + else if (cp[1] == 'S' || cp[1] == 's') + { + fill = STACCATO; + ++cp; + slen--; + } + break; + } + } +} + +/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** + * + * This section implements driver hooks to run playstring() and the tone(), + * endtone(), and rest() functions defined above. + */ + +static int spkr_active; /* exclusion flag */ +static struct buf *spkr_inbuf; /* incoming buf */ + +int spkropen(dev) +dev_t dev; +{ +#ifdef DEBUG + printf("spkropen: entering with dev = %x\n", dev); +#endif /* DEBUG */ + + if (minor(dev) != 0) + return(ENXIO); + else if (spkr_active) + return(EBUSY); + else + { + playinit(); + spkr_inbuf = geteblk(DEV_BSIZE); + spkr_active = 1; + } + return(0); +} + +int spkrwrite(dev, uio) +dev_t dev; +struct uio *uio; +{ + register unsigned n; + char *cp; + int error; +#ifdef DEBUG + printf("spkrwrite: entering with dev = %x, count = %d\n", + dev, uio->uio_resid); +#endif /* DEBUG */ + + if (minor(dev) != 0) + return(ENXIO); + else + { + n = MIN(DEV_BSIZE, uio->uio_resid); + cp = spkr_inbuf->b_un.b_addr; + error = uiomove(cp, n, uio); + if (!error) + playstring(cp, n); + return(error); + } +} + +int spkrclose(dev) +dev_t dev; +{ +#ifdef DEBUG + printf("spkrclose: entering with dev = %x\n", dev); +#endif /* DEBUG */ + + if (minor(dev) != 0) + return(ENXIO); + else + { + endtone(); + brelse(spkr_inbuf); + spkr_active = 0; + } + return(0); +} + +int spkrioctl(dev, cmd, cmdarg) +dev_t dev; +int cmd; +caddr_t cmdarg; +{ +#ifdef DEBUG + printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd); +#endif /* DEBUG */ + + if (minor(dev) != 0) + return(ENXIO); + else if (cmd == SPKRTONE) + { + tone_t *tp = (tone_t *)cmdarg; + + if (tp->frequency == 0) + rest(tp->duration); + else + tone(tp->frequency, tp->duration); + } + else if (cmd == SPKRTUNE) + { + tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); + tone_t ttp; + int error; + + for (; ; tp++) { + error = copyin(tp, &ttp, sizeof(tone_t)); + if (error) + return(error); + if (ttp.duration == 0) + break; + if (ttp.frequency == 0) + rest(ttp.duration); + else + tone(ttp.frequency, ttp.duration); + } + } + else + return(EINVAL); + return(0); +} + +#endif /* NSPEAKER > 0 */ +/* spkr.c ends here */ diff --git a/sys/i386/isa/timerreg.h b/sys/i386/isa/timerreg.h new file mode 100644 index 000000000000..72c70227e3ed --- /dev/null +++ b/sys/i386/isa/timerreg.h @@ -0,0 +1,89 @@ +/*- + * 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. + * + * $Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp $ + * + * 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. + */ + +/* + * 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/i386/isa/ultra14f.c b/sys/i386/isa/ultra14f.c new file mode 100644 index 000000000000..46626b7ff93c --- /dev/null +++ b/sys/i386/isa/ultra14f.c @@ -0,0 +1,1308 @@ +/* + * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu) + * Thanks to Julian Elischer for advice and help with this port. + * + * Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * commenced: Sun Sep 27 18:14:01 PDT 1992 + */ + +#include <sys/types.h> +#include <uha.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/user.h> + +#ifdef MACH /* EITHER CMU OR OSF */ +#include <i386/ipl.h> +#include <i386at/scsi.h> +#include <i386at/scsiconf.h> + +#ifdef OSF /* OSF ONLY */ +#include <sys/table.h> +#include <i386/handler.h> +#include <i386/dispatcher.h> +#include <i386/AT386/atbus.h> + +#else OSF /* CMU ONLY */ +#include <i386at/atbus.h> +#include <i386/pio.h> +#endif OSF +#endif MACH /* end of MACH specific */ + +#ifdef __386BSD__ /* 386BSD specific */ +#define isa_dev isa_device +#define dev_unit id_unit +#define dev_addr id_iobase + +#include <i386/include/pio.h> +#include <i386/isa/isa_device.h> +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> +#endif __386BSD__ + +/**/ + +#ifdef __386BSD__ +#include "ddb.h" +#if NDDB > 0 +int Debugger(); +#else NDDB +#define Debugger() panic("should call debugger here") +#endif NDDB +#endif __386BSD__ + +#ifdef MACH +int Debugger(); +#endif MACH + +typedef struct {unsigned char addr[4]; } physaddr; +typedef struct {unsigned char len[4]; } physlen; + + +#ifdef MACH +extern physaddr kvtophys(); +#define PHYSTOKV(x) phystokv(x) +#define KVTOPHYS(x) kvtophys(x) +#endif MACH + +#ifdef __386BSD__ +#define PHYSTOKV(x) (x | 0xFE000000) +#define KVTOPHYS(x) vtophys(x) +#endif __386BSD__ + +extern int delaycount; /* from clock setup code */ +#define NUM_CONCURRENT 16 /* number of concurrent ops per board */ +#define UHA_NSEG 33 /* number of dma segments supported */ +#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */ +/**/ +/************************** board definitions *******************************/ +/* + * I/O Port Interface +*/ + #define UHA_LMASK (0x000) /* local doorbell mask reg */ + #define UHA_LINT (0x001) /* local doorbell int/stat reg */ + #define UHA_SMASK (0x002) /* system doorbell mask reg */ + #define UHA_SINT (0x003) /* system doorbell int/stat reg */ + #define UHA_ID0 (0x004) /* product id reg 0 */ + #define UHA_ID1 (0x005) /* product id reg 1 */ + #define UHA_CONF1 (0x006) /* config reg 1 */ + #define UHA_CONF2 (0x007) /* config reg 2 */ + #define UHA_OGM0 (0x008) /* outgoing mail ptr 0 least sig */ + #define UHA_OGM1 (0x009) /* outgoing mail ptr 1 least mid */ + #define UHA_OGM2 (0x00a) /* outgoing mail ptr 2 most mid */ + #define UHA_OGM3 (0x00b) /* outgoing mail ptr 3 most sig */ + #define UHA_ICM0 (0x00c) /* incoming mail ptr 0 */ + #define UHA_ICM1 (0x00d) /* incoming mail ptr 1 */ + #define UHA_ICM2 (0x00e) /* incoming mail ptr 2 */ + #define UHA_ICM3 (0x00f) /* incoming mail ptr 3 */ + + /* +* UHA_LMASK bits (read only) +*/ + +#define UHA_LDIE 0x80 /* local doorbell int enabled */ +#define UHA_SRSTE 0x40 /* soft reset enabled */ +#define UHA_ABORTEN 0x10 /* abort MSCP enabled */ +#define UHA_OGMINTEN 0x01 /* outgoing mail interrupt enabled */ + +/* +* UHA_LINT bits (read) +*/ + +#define UHA_LDIP 0x80 /* local doorbell int pending */ + +/* +* UHA_LINT bits (write) +*/ + +#define UHA_ADRST 0x40 /* adapter soft reset */ +#define UHA_SBRST 0x20 /* scsi bus reset */ +#define UHA_ASRST 0x60 /* adapter and scsi reset */ +#define UHA_ABORT 0x10 /* abort MSCP */ +#define UHA_OGMINT 0x01 /* tell adapter to get mail */ + +/* +* UHA_SMASK bits (read) +*/ + +#define UHA_SINTEN 0x80 /* system doorbell interupt Enabled */ +#define UHA_ABORT_COMPLETE_EN 0x10 /* abort MSCP command complete int Enabled */ +#define UHA_ICM_ENABLED 0x01 /* ICM interrupt enabled + +/* +* UHA_SMASK bits (write) +*/ + +#define UHA_ENSINT 0x80 /* enable system doorbell interrupt */ +#define UHA_EN_ABORT_COMPLETE 0x10 /* enable abort MSCP complete int */ +#define UHA_ENICM 0x01 /* enable ICM interrupt */ + +/* +* UHA_SINT bits (read) +*/ + +#define UHA_SINTP 0x80 /* system doorbell int pending */ +#define UHA_ABORT_SUCC 0x10 /* abort MSCP successful */ +#define UHA_ABORT_FAIL 0x18 /* abort MSCP failed */ + +/* +* UHA_SINT bits (write) +*/ + +#define UHA_ABORT_ACK 0x18 /* acknowledge status and clear */ +#define UHA_ICM_ACK 0x01 /* acknowledge ICM and clear */ + +/* +* UHA_CONF1 bits (read only) +*/ + +#define UHA_DMA_CH5 0x00 /* DMA channel 5 */ +#define UHA_DMA_CH6 0x40 /* 6 */ +#define UHA_DMA_CH7 0x80 /* 7 */ +#define UHA_IRQ15 0x00 /* IRQ 15 */ +#define UHA_IRQ14 0x10 /* 14 */ +#define UHA_IRQ11 0x20 /* 11 */ +#define UHA_IRQ10 0x30 /* 10 */ + +/*********************************** +* ha_status error codes +\***********************************/ + +#define UHA_NO_ERR 0x00 /* No error supposedly */ +#define UHA_SBUS_ABORT_ERR 0x84 /* scsi bus abort error */ +#define UHA_SBUS_TIMEOUT 0x91 /* scsi bus selection timeout */ +#define UHA_SBUS_OVER_UNDER 0x92 /* scsi bus over/underrun */ +#define UHA_BAD_SCSI_CMD 0x96 /* illegal scsi command */ +#define UHA_AUTO_SENSE_ERR 0x9b /* auto request sense err */ +#define UHA_SBUS_RES_ERR 0xa3 /* scsi bus reset error */ +#define UHA_BAD_SG_LIST 0xff /* invalid scatter gath list */ + +/**/ + +struct uha_dma_seg +{ + physaddr addr; + physlen len; +}; +/**/ + +struct mscp +{ + unsigned char opcode:3; + #define U14_HAC 0x01 /*host adapter command*/ + #define U14_TSP 0x02 /*target scsi pass through command*/ + #define U14_SDR 0x04 /*scsi device reset*/ + unsigned char xdir:2; /*xfer direction*/ + #define U14_SDET 0x00 /*determined by scsi command*/ + #define U14_SDIN 0x01 /*scsi data in*/ + #define U14_SDOUT 0x02 /*scsi data out*/ + #define U14_NODATA 0x03 /*no data xfer*/ + unsigned char dcn:1; /*disable disconnect for this command*/ + unsigned char ca:1; /*Cache control*/ + unsigned char sgth:1; /*scatter gather flag*/ + unsigned char target:3; + unsigned char chan:2; /*scsi channel (always 0 for 14f)*/ + unsigned char lun:3; + physaddr data; + physlen datalen; + physaddr link; + unsigned char link_id; + unsigned char sg_num; /*number of scat gath segs */ + /*in s-g list if sg flag is*/ + /*set. starts at 1, 8bytes per*/ + unsigned char senselen; + unsigned char cdblen; + unsigned char cdb[12]; + unsigned char ha_status; + unsigned char targ_status; + physaddr sense; /* if 0 no auto sense */ + /*-----------------end of hardware supported fields----------------*/ + struct mscp *next; /* in free list */ + struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ + long int delta; /* difference from previous*/ + struct mscp *later,*sooner; + int flags; +#define MSCP_FREE 0 +#define MSCP_ACTIVE 1 +#define MSCP_ABORTED 2 + struct uha_dma_seg uha_dma[UHA_NSEG]; + struct scsi_sense_data mscp_sense; +}; + +struct mscp *uha_soonest = (struct mscp *)0; +struct mscp *uha_latest = (struct mscp *)0; +long int uha_furtherest = 0; /* longest time in the timeout queue */ +/**/ + +struct uha_data +{ + int flags; +#define UHA_INIT 0x01; + int baseport; + struct mscp mscps[NUM_CONCURRENT]; + struct mscp *free_mscp; + int our_id; /* our scsi id */ + int vect; + int dma; +} uha_data[NUHA]; + +int uhaprobe(); +int uha_attach(); +int uhaintr(); +int uha_scsi_cmd(); +int uha_timeout(); +int uha_abort(); +struct mscp *cheat; +void uhaminphys(); +long int uha_adapter_info(); + +unsigned long int scratch; + +#ifdef MACH +struct isa_driver uhadriver = { uhaprobe, 0, uha_attach, "uha", 0, 0, 0}; +int (*uhaintrs[])() = {uhaintr, 0}; +#endif MACH + +#ifdef __386BSD__ +struct isa_driver uhadriver = { uhaprobe, uha_attach, "uha"}; +#endif __386BSD__ + +static uha_unit = 0; +int uha_debug = 0; +#define UHA_SHOWMSCPS 0x01 +#define UHA_SHOWINTS 0x02 +#define UHA_SHOWCMDS 0x04 +#define UHA_SHOWMISC 0x08 +#define FAIL 1 +#define SUCCESS 0 +#define PAGESIZ 4096 + +struct scsi_switch uha_switch = +{ + uha_scsi_cmd, + uhaminphys, + 0, + 0, + uha_adapter_info, + 0,0,0 +}; + +/**/ +/***********************************************************************\ +* Function to send a command out through a mailbox * +\***********************************************************************/ +uha_send_mbox( int unit + ,struct mscp *mscp) +{ + int port = uha_data[unit].baseport; + int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ + int s = splbio(); + + while( ((inb(port + UHA_LINT) & (UHA_LDIP)) + != (0)) + && (spincount--)); + if(spincount == -1) + { + printf("uha%d: board not responding\n",unit); + Debugger(); + } + + outl(port + UHA_OGM0,KVTOPHYS(mscp)); + outb(port + UHA_LINT, (UHA_OGMINT)); + splx(s); +} + +/***********************************************************************\ +* Function to send abort to 14f * +\***********************************************************************/ + +uha_abort( int unit + ,struct mscp *mscp) +{ + int port = uha_data[unit].baseport; + int spincount = FUDGE(delaycount) * 1; + int abortcount = FUDGE(delaycount) * 2000; + int s = splbio(); + + while(((inb(port + UHA_LINT) & (UHA_LDIP)) + != (0)) + && (spincount--)); + if(spincount == -1); + { + printf("uha%d: board not responding\n",unit); + Debugger(); + } + + outl(port + UHA_OGM0,KVTOPHYS(mscp)); + outb(port + UHA_LINT,UHA_ABORT); + + while((abortcount--) && (!(inb(port + UHA_SINT) & UHA_ABORT_FAIL))); + if(abortcount == -1) + { + printf("uha%d: board not responding\n",unit); + Debugger(); + } + if((inb(port + UHA_SINT) & 0x10) != 0) + { + outb(port + UHA_SINT,UHA_ABORT_ACK); + return(1); + } + else + { + outb(port + UHA_SINT,UHA_ABORT_ACK); + return(0); + } +} + +/***********************************************************************\ +* Function to poll for command completion when in poll mode * +\***********************************************************************/ +uha_poll(int unit ,int wait) /* in msec */ +{ + int port = uha_data[unit].baseport; + int spincount = FUDGE(delaycount) * wait; /* in msec */ + int stport = port + UHA_SINT; + int start = spincount; + +retry: + while( (spincount--) && (!(inb(stport) & UHA_SINTP))); + if(spincount == -1) + { + printf("uha%d: board not responding\n",unit); + return(EIO); + } +if ((int)cheat != PHYSTOKV(inl(port + UHA_ICM0))) +{ + printf("discarding %x ",inl(port + UHA_ICM0)); + outb(port + UHA_SINT, UHA_ICM_ACK); + spinwait(50); + goto retry; +}/* don't know this will work */ + uhaintr(unit); + return(0); +} + +/*******************************************************\ +* Check if the device can be found at the port given * +* and if so, set it up ready for further work * +* as an argument, takes the isa_dev structure from * +* autoconf.c * +\*******************************************************/ +uhaprobe(dev) +struct isa_dev *dev; +{ + int unit = uha_unit; + dev->dev_unit = unit; + uha_data[unit].baseport = dev->dev_addr; + if(unit >= NUHA) + { + printf("uha: unit number (%d) too high\n",unit); + return(0); + } + + /*try and initialize unit at this location*/ + if (uha_init(unit) != 0) + { + return(0); + } + + /* if its there put in it's interrupt and DRQ vectors */ + + dev->id_irq = (1 << uha_data[unit].vect); + dev->id_drq = uha_data[unit].dma; + + + uha_unit ++; +return(1); +} + +/***********************************************\ +* Attach all the sub-devices we can find * +\***********************************************/ +uha_attach(dev) +struct isa_dev *dev; +{ + int unit = dev->dev_unit; + + +#ifdef __386BSD__ + printf(" probing for scsi devices**\n"); +#endif __386BSD__ + + /***********************************************\ + * ask the adapter what subunits are present * + \***********************************************/ + scsi_attachdevs( unit, uha_data[unit].our_id, &uha_switch); + +#if defined(OSF) + uha_attached[unit]=1; +#endif /* defined(OSF) */ + if(!unit) /* only one for all boards */ + { + uha_timeout(0); + } + + +#ifdef __386BSD__ + printf("uha%d",unit); +#endif __386BSD__ + return; +} + +/***********************************************\ +* Return some information to the caller about * +* the adapter and it's capabilities * +\***********************************************/ +long int uha_adapter_info(unit) +int unit; +{ + return(2); /* 2 outstanding requests at a time per device */ +} + +/***********************************************\ +* Catch an interrupt from the adaptor * +\***********************************************/ +uhaintr(unit) +{ + struct mscp *mscp; + u_char uhastat; + unsigned long int mboxval; + + int port = uha_data[unit].baseport; + + + if(scsi_debug & PRINTROUTINES) + printf("uhaintr "); + +#if defined(OSF) + if (!uha_attached[unit]) + { + return(1); + } +#endif /* defined(OSF) */ + while(inb(port + UHA_SINT) & UHA_SINTP) + { + /***********************************************\ + * First get all the information and then * + * acknowlege the interrupt * + \***********************************************/ + uhastat = inb(port + UHA_SINT); + mboxval = inl(port + UHA_ICM0); + outb(port + UHA_SINT,UHA_ICM_ACK); + + if(scsi_debug & TRACEINTERRUPTS) + printf("status = 0x%x ",uhastat); + /***********************************************\ + * Process the completed operation * + \***********************************************/ + + mscp = (struct mscp *)(PHYSTOKV(mboxval)); + + if(uha_debug & UHA_SHOWCMDS ) + { + uha_show_scsi_cmd(mscp->xs); + } + if((uha_debug & UHA_SHOWMSCPS) && mscp) + printf("<int mscp(%x)>",mscp); + uha_remove_timeout(mscp); + + uha_done(unit,mscp); + } + return(1); +} + +/***********************************************\ +* We have a mscp which has been processed by the * +* adaptor, now we look to see how the operation * +* went. * +\***********************************************/ + +uha_done(unit,mscp) +int unit; +struct mscp *mscp; +{ + struct scsi_sense_data *s1,*s2; + struct scsi_xfer *xs = mscp->xs; + + if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) + printf("uha_done "); + /***********************************************\ + * Otherwise, put the results of the operation * + * into the xfer and call whoever started it * + \***********************************************/ + if ( (mscp->ha_status == UHA_NO_ERR) || (xs->flags & SCSI_ERR_OK)) + { /* All went correctly OR errors expected */ + xs->resid = 0; + xs->error = 0; + } + else + { + + s1 = &(mscp->mscp_sense); + s2 = &(xs->sense); + + if(mscp->ha_status != UHA_NO_ERR) + { + switch(mscp->ha_status) + { + case UHA_SBUS_TIMEOUT: /* No response */ + if (uha_debug & UHA_SHOWMISC) + { + printf("timeout reported back\n"); + } + xs->error = XS_TIMEOUT; + break; + case UHA_SBUS_OVER_UNDER: + if (uha_debug & UHA_SHOWMISC) + { + printf("scsi bus xfer over/underrun\n"); + } + xs->error = XS_DRIVER_STUFFUP; + break; + case UHA_BAD_SG_LIST: + if (uha_debug & UHA_SHOWMISC) + { + printf("bad sg list reported back\n"); + } + xs->error = XS_DRIVER_STUFFUP; + break; + default: /* Other scsi protocol messes */ + xs->error = XS_DRIVER_STUFFUP; + if (uha_debug & UHA_SHOWMISC) + { + printf("unexpected ha_status: %x\n", + mscp->ha_status); + } + } + + } + else + { + + if (mscp->targ_status != 0) +/**************************************************************************\ +* I have no information for any possible value of target status field * +* other than 0 means no error!! So I guess any error is unexpected in that * +* event!! * +\**************************************************************************/ + + { + if (uha_debug & UHA_SHOWMISC) + { + printf("unexpected targ_status: %x\n", + mscp->targ_status); + } + xs->error = XS_DRIVER_STUFFUP; + } + } + } +done: xs->flags |= ITSDONE; + uha_free_mscp(unit,mscp, xs->flags); + if(xs->when_done) + (*(xs->when_done))(xs->done_arg,xs->done_arg2); +} + +/***********************************************\ +* A mscp (and hence a mbx-out is put onto the * +* free list. * +\***********************************************/ +uha_free_mscp(unit,mscp, flags) +struct mscp *mscp; +{ + unsigned int opri; + + if(scsi_debug & PRINTROUTINES) + printf("mscp%d(0x%x)> ",unit,flags); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + + mscp->next = uha_data[unit].free_mscp; + uha_data[unit].free_mscp = mscp; + mscp->flags = MSCP_FREE; + /***********************************************\ + * If there were none, wake abybody waiting for * + * one to come free, starting with queued entries* + \***********************************************/ + if (!mscp->next) { + wakeup(&uha_data[unit].free_mscp); + } + if (!(flags & SCSI_NOMASK)) + splx(opri); +} + +/***********************************************\ +* Get a free mscp (and hence mbox-out entry) * +\***********************************************/ +struct mscp * +uha_get_mscp(unit,flags) +{ + unsigned opri; + struct mscp *rc; + + if(scsi_debug & PRINTROUTINES) + printf("<mscp%d(0x%x) ",unit,flags); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + /***********************************************\ + * If we can and have to, sleep waiting for one * + * to come free * + \***********************************************/ + while ((!(rc = uha_data[unit].free_mscp)) && (!(flags & SCSI_NOSLEEP))) + { + sleep(&uha_data[unit].free_mscp, PRIBIO); + } + if (rc) + { + uha_data[unit].free_mscp = rc->next; + rc->flags = MSCP_ACTIVE; + } + if (!(flags & SCSI_NOMASK)) + splx(opri); + return(rc); +} + + + +/***********************************************\ +* Start the board, ready for normal operation * +\***********************************************/ + +uha_init(unit) +int unit; +{ + unsigned char ad[4]; + volatile unsigned char model; + volatile unsigned char submodel; + unsigned char config_reg1; + unsigned char config_reg2; + unsigned char dma_ch; + unsigned char irq_ch; + unsigned char uha_id; + int port = uha_data[unit].baseport; + int i; + int resetcount = FUDGE(delaycount) * 4000; + + model = inb(port + UHA_ID0); + submodel = inb(port + UHA_ID1); + if ((model != 0x56) & (submodel != 0x40)) + { printf("ultrastor 14f not responding\n"); + return(ENXIO); } + + printf("uha%d reading board settings, ",unit); + + config_reg1 = inb(port + UHA_CONF1); + config_reg2 = inb(port + UHA_CONF2); + dma_ch = (config_reg1 & 0xc0); + irq_ch = (config_reg1 & 0x30); + uha_id = (config_reg2 & 0x07); + + switch(dma_ch) + { + case UHA_DMA_CH5: + uha_data[unit].dma = 5; + printf("dma=5 "); + break; + case UHA_DMA_CH6: + uha_data[unit].dma = 6; + printf("dma=6 "); + break; + case UHA_DMA_CH7: + uha_data[unit].dma = 7; + printf("dma=7 "); + break; + default: + printf("illegal dma jumper setting\n"); + return(EIO); + } + switch(irq_ch) + { + case UHA_IRQ10: + uha_data[unit].vect = 10; + printf("int=10 "); + break; + case UHA_IRQ11: + uha_data[unit].vect = 11; + printf("int=11 "); + break; + case UHA_IRQ14: + uha_data[unit].vect = 14; + printf("int=14 "); + break; + case UHA_IRQ15: + uha_data[unit].vect = 15; + printf("int=15 "); + break; + default: + printf("illegal int jumper setting\n"); + return(EIO); + } + /* who are we on the scsi bus */ + printf("id=%x\n",uha_id); + uha_data[unit].our_id = uha_id; + + + /***********************************************\ + * link up all our MSCPs into a free list * + \***********************************************/ + for (i=0; i < NUM_CONCURRENT; i++) + { + uha_data[unit].mscps[i].next = uha_data[unit].free_mscp; + uha_data[unit].free_mscp = &uha_data[unit].mscps[i]; + uha_data[unit].free_mscp->flags = MSCP_FREE; + } + + /***********************************************\ + * Note that we are going and return (to probe) * + \***********************************************/ + outb(port + UHA_LINT, UHA_ASRST); + while( (resetcount--) && (!(inb(port + UHA_LINT)))); + if(resetcount == -1) + { + printf("uha%d: board timed out during reset\n",unit); + return(ENXIO); + } + + outb(port + UHA_SMASK, 0x81); /* make sure interrupts are enabled */ + uha_data[unit].flags |= UHA_INIT; + return(0); +} + + + +#ifndef min +#define min(x,y) (x < y ? x : y) +#endif min + + +void uhaminphys(bp) +struct buf *bp; +{ +#ifdef MACH +#if !defined(OSF) + bp->b_flags |= B_NPAGES; /* can support scat/gather */ +#endif /* defined(OSF) */ +#endif MACH + if(bp->b_bcount > ((UHA_NSEG-1) * PAGESIZ)) + { + bp->b_bcount = ((UHA_NSEG-1) * PAGESIZ); + } +} + +/***********************************************\ +* start a scsi operation given the command and * +* the data address. Also needs the unit, target * +* and lu * +\***********************************************/ +int uha_scsi_cmd(xs) +struct scsi_xfer *xs; +{ + struct scsi_sense_data *s1,*s2; + struct mscp *mscp; + struct uha_dma_seg *sg; + int seg; /* scatter gather seg being worked on */ + int i = 0; + int rc = 0; + int thiskv; + unsigned long int thisphys,nextphys; + int unit =xs->adapter; + int bytes_this_seg,bytes_this_page,datalen,flags; + struct iovec *iovp; + int s; + unsigned int stat; + int port = uha_data[unit].baseport; + unsigned long int templen; + + + if(scsi_debug & PRINTROUTINES) + printf("uha_scsi_cmd "); + /***********************************************\ + * get a mscp (mbox-out) to use. If the transfer * + * is from a buf (possibly from interrupt time) * + * then we can't allow it to sleep * + \***********************************************/ + flags = xs->flags; + if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ + if(flags & ITSDONE) + { + printf("Already done?"); + xs->flags &= ~ITSDONE; + } + if(!(flags & INUSE)) + { + printf("Not in use?"); + xs->flags |= INUSE; + } + if (!(mscp = uha_get_mscp(unit,flags))) + { + xs->error = XS_DRIVER_STUFFUP; + return(TRY_AGAIN_LATER); + } + +cheat = mscp; + if(uha_debug & UHA_SHOWMSCPS) + printf("<start mscp(%x)>",mscp); + if(scsi_debug & SHOWCOMMANDS) + { + uha_show_scsi_cmd(xs); + } + mscp->xs = xs; + /***********************************************\ + * Put all the arguments for the xfer in the mscp * + \***********************************************/ + + if (flags & SCSI_RESET) + { + mscp->opcode = 0x04; + mscp->ca = 0x01; + } + else + { + mscp->opcode = 0x02; + mscp->ca = 0x01; + } + + if (flags & SCSI_DATA_IN) + { + mscp->xdir = 0x01; + } + if (flags & SCSI_DATA_OUT) + { + mscp->xdir = 0x02; + } + + if (xs->lu != 0) + { + xs->error = XS_DRIVER_STUFFUP; + uha_free_mscp(unit,mscp,flags); + return(HAD_ERROR); + } + + mscp->dcn = 0x00; + mscp->chan = 0x00; + mscp->target = xs->targ; + mscp->lun = xs->lu; + mscp->link.addr[0] = 0x00; + mscp->link.addr[1] = 0x00; + mscp->link.addr[2] = 0x00; + mscp->link.addr[3] = 0x00; + mscp->link_id = 0x00; + mscp->cdblen = xs->cmdlen; + scratch = KVTOPHYS(&(mscp->mscp_sense)); + mscp->sense.addr[0] = (scratch & 0xff); + mscp->sense.addr[1] = ((scratch >> 8) & 0xff); + mscp->sense.addr[2] = ((scratch >> 16) & 0xff); + mscp->sense.addr[3] = ((scratch >> 24) & 0xff); + mscp->senselen = sizeof(mscp->mscp_sense); + mscp->ha_status = 0x00; + mscp->targ_status = 0x00; + + if(xs->datalen) + { /* should use S/G only if not zero length */ + scratch = KVTOPHYS(mscp->uha_dma); + mscp->data.addr[0] = (scratch & 0xff); + mscp->data.addr[1] = ((scratch >> 8) & 0xff); + mscp->data.addr[2] = ((scratch >> 16) & 0xff); + mscp->data.addr[3] = ((scratch >> 24) & 0xff); + sg = mscp->uha_dma ; + seg = 0; + mscp->sgth = 0x01; + + if(flags & SCSI_DATA_UIO) + { + iovp = ((struct uio *)xs->data)->uio_iov; + datalen = ((struct uio *)xs->data)->uio_iovcnt; + xs->datalen = 0; + while ((datalen) && (seg < UHA_NSEG)) + { + scratch = (unsigned long)iovp->iov_base; + sg->addr.addr[0] = (scratch & 0xff); + sg->addr.addr[1] = ((scratch >> 8) & 0xff); + sg->addr.addr[2] = ((scratch >> 16) & 0xff); + sg->addr.addr[3] = ((scratch >> 24) & 0xff); + xs->datalen += *(unsigned long *)sg->len.len = iovp->iov_len; + if(scsi_debug & SHOWSCATGATH) + printf("(0x%x@0x%x)" + ,iovp->iov_len + ,iovp->iov_base); + sg++; + iovp++; + seg++; + datalen--; + } + } + else + { + /***********************************************\ + * Set up the scatter gather block * + \***********************************************/ + + if(scsi_debug & SHOWSCATGATH) + printf("%d @0x%x:- ",xs->datalen,xs->data); + datalen = xs->datalen; + thiskv = (int)xs->data; + thisphys = KVTOPHYS(thiskv); + templen = 0; + + while ((datalen) && (seg < UHA_NSEG)) + { + bytes_this_seg = 0; + + /* put in the base address */ + sg->addr.addr[0] = (thisphys & 0xff); + sg->addr.addr[1] = ((thisphys >> 8) & 0xff); + sg->addr.addr[2] = ((thisphys >> 16) & 0xff); + sg->addr.addr[3] = ((thisphys >> 24) & 0xff); + + if(scsi_debug & SHOWSCATGATH) + printf("0x%x",thisphys); + + /* do it at least once */ + nextphys = thisphys; + while ((datalen) && (thisphys == nextphys)) + /*********************************************\ + * This page is contiguous (physically) with * + * the the last, just extend the length * + \*********************************************/ + { + /* how far to the end of the page */ + nextphys = (thisphys & (~(PAGESIZ - 1))) + + PAGESIZ; + bytes_this_page = nextphys - thisphys; + /**** or the data ****/ + bytes_this_page = min(bytes_this_page + ,datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; + + /* get more ready for the next page */ + thiskv = (thiskv & (~(PAGESIZ - 1))) + + PAGESIZ; + if(datalen) + thisphys = KVTOPHYS(thiskv); + } + /********************************************\ + * next page isn't contiguous, finish the seg * + \********************************************/ + if(scsi_debug & SHOWSCATGATH) + printf("(0x%x)",bytes_this_seg); + sg->len.len[0] = (bytes_this_seg & 0xff); + sg->len.len[1] = ((bytes_this_seg >> 8) & 0xff); + sg->len.len[2] = ((bytes_this_seg >> 16) & 0xff); + sg->len.len[3] = ((bytes_this_seg >> 24) & 0xff); + templen += bytes_this_seg; + sg++; + seg++; + } + } /*end of iov/kv decision */ + mscp->datalen.len[0] = (templen & 0xff); + mscp->datalen.len[1] = ((templen >> 8) & 0xff); + mscp->datalen.len[2] = ((templen >> 16) & 0xff); + mscp->datalen.len[3] = ((templen >> 24) & 0xff); + mscp->sg_num = seg; + + if(scsi_debug & SHOWSCATGATH) + printf("\n"); + if (datalen) + { /* there's still data, must have run out of segs! */ + printf("uha_scsi_cmd%d: more than %d DMA segs\n", + unit,UHA_NSEG); + xs->error = XS_DRIVER_STUFFUP; + uha_free_mscp(unit,mscp,flags); + return(HAD_ERROR); + } + + } + else + { /* No data xfer, use non S/G values */ + mscp->data.addr[0] = 0x00; + mscp->data.addr[1] = 0x00; + mscp->data.addr[2] = 0x00; + mscp->data.addr[3] = 0x00; + mscp->datalen.len[0] = 0x00; + mscp->datalen.len[1] = 0x00; + mscp->datalen.len[2] = 0x00; + mscp->datalen.len[3] = 0x00; + mscp->xdir = 0x03; + mscp->sgth = 0x00; + mscp->sg_num = 0x00; + } + + /***********************************************\ + * Put the scsi command in the mscp and start it * + \***********************************************/ + bcopy(xs->cmd, mscp->cdb, xs->cmdlen); + + /***********************************************\ + * Usually return SUCCESSFULLY QUEUED * + \***********************************************/ + if (!(flags & SCSI_NOMASK)) + { + s = splbio(); + uha_send_mbox(unit,mscp); + uha_add_timeout(mscp,xs->timeout); + splx(s); + if(scsi_debug & TRACEINTERRUPTS) + printf("cmd_sent "); + return(SUCCESSFULLY_QUEUED); + } + /***********************************************\ + * If we can't use interrupts, poll on completion* + \***********************************************/ + uha_send_mbox(unit,mscp); + if(scsi_debug & TRACEINTERRUPTS) + printf("cmd_wait "); + do + { + if(uha_poll(unit,xs->timeout)) + { + if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n"); + if(!(uha_abort(unit,mscp))) + { + printf("abort failed in wait\n"); + uha_free_mscp(unit,mscp,flags); + } + xs->error = XS_DRIVER_STUFFUP; + splx(s); + return(HAD_ERROR); + } + } while (!(xs->flags & ITSDONE));/* something (?) else finished */ + splx(s); +scsi_debug = 0;uha_debug = 0; + if(xs->error) + { + return(HAD_ERROR); + } + return(COMPLETE); +} + +/* + * +----------+ +----------+ +----------+ + * uha_soonest--->| later |--->| later|--->| later|--->0 + * | [Delta] | | [Delta] | | [Delta] | + * 0<---|sooner |<---|sooner |<---|sooner |<---uha_latest + * +----------+ +----------+ +----------+ + * + * uha_furtherest = sum(Delta[1..n]) + */ +uha_add_timeout(mscp,time) +struct mscp *mscp; +int time; +{ + int timeprev; + struct mscp *prev; + int s = splbio(); + + if(prev = uha_latest) /* yes, an assign */ + { + timeprev = uha_furtherest; + } + else + { + timeprev = 0; + } + while(prev && (timeprev > time)) + { + timeprev -= prev->delta; + prev = prev->sooner; + } + if(prev) + { + mscp->delta = time - timeprev; + if( mscp->later = prev->later) /* yes an assign */ + { + mscp->later->sooner = mscp; + mscp->later->delta -= mscp->delta; + } + else + { + uha_furtherest = time; + uha_latest = mscp; + } + mscp->sooner = prev; + prev->later = mscp; + } + else + { + if( mscp->later = uha_soonest) /* yes, an assign*/ + { + mscp->later->sooner = mscp; + mscp->later->delta -= time; + } + else + { + uha_furtherest = time; + uha_latest = mscp; + } + mscp->delta = time; + mscp->sooner = (struct mscp *)0; + uha_soonest = mscp; + } + splx(s); +} + +uha_remove_timeout(mscp) +struct mscp *mscp; +{ + int s = splbio(); + + if(mscp->sooner) + { + mscp->sooner->later = mscp->later; + } + else + { + uha_soonest = mscp->later; + } + if(mscp->later) + { + mscp->later->sooner = mscp->sooner; + mscp->later->delta += mscp->delta; + } + else + { + uha_latest = mscp->sooner; + uha_furtherest -= mscp->delta; + } + mscp->sooner = mscp->later = (struct mscp *)0; + splx(s); +} + + +extern int hz; +#define ONETICK 500 /* milliseconds */ +#define SLEEPTIME ((hz * 1000) / ONETICK) +uha_timeout(arg) +int arg; +{ + struct mscp *mscp; + int unit; + int s = splbio(); + unsigned int stat; + int port = uha_data[unit].baseport; + + while( mscp = uha_soonest ) + { + if(mscp->delta <= ONETICK) + /***********************************************\ + * It has timed out, we need to do some work * + \***********************************************/ + { + unit = mscp->xs->adapter; + printf("uha%d:%d device timed out\n",unit + ,mscp->xs->targ); + if(uha_debug & UHA_SHOWMSCPS) + uha_print_active_mscp(); + + /***************************************\ + * Unlink it from the queue * + \***************************************/ + uha_remove_timeout(mscp); + + if((uha_abort(unit,mscp) !=1) || (mscp->flags = MSCP_ABORTED)) + { + printf("AGAIN"); + mscp->xs->retries = 0; /* I MEAN IT ! */ + uha_done(unit,mscp,FAIL); + } + else /* abort the operation that has timed out */ + { + printf("\n"); + uha_add_timeout(mscp,2000 + ONETICK); + mscp->flags = MSCP_ABORTED; + } + } + else + /***********************************************\ + * It has not timed out, adjust and leave * + \***********************************************/ + { + mscp->delta -= ONETICK; + uha_furtherest -= ONETICK; + break; + } + } + splx(s); + timeout(uha_timeout,arg,SLEEPTIME); +} + +uha_show_scsi_cmd(struct scsi_xfer *xs) +{ + u_char *b = (u_char *)xs->cmd; + int i = 0; + if(!(xs->flags & SCSI_RESET)) + { + printf("uha%d:%d:%d-" + ,xs->adapter + ,xs->targ + ,xs->lu); + while(i < xs->cmdlen ) + { + if(i) printf(","); + printf("%x",b[i++]); + } + printf("-\n"); + } + else + { + printf("uha%d:%d:%d-RESET-\n" + ,xs->adapter + ,xs->targ + ,xs->lu + ); + } +} +uha_print_mscp(mscp) +struct mscp *mscp; +{ + printf("mscp:%x op:%x cmdlen:%d senlen:%d\n" + ,mscp + ,mscp->opcode + ,mscp->cdblen + ,mscp->senselen); + printf(" sg:%d sgnum:%x datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n" + ,mscp->sgth + ,mscp->sg_num + ,mscp->datalen + ,mscp->ha_status + ,mscp->targ_status + ,mscp->delta + ,mscp->flags); + uha_show_scsi_cmd(mscp->xs); +} + +uha_print_active_mscp() +{ + struct mscp *mscp; + mscp = uha_soonest; + + while(mscp) + { + uha_print_mscp(mscp); + mscp = mscp->later; + } + printf("Furtherest = %d\n",uha_furtherest); +} diff --git a/sys/i386/isa/vector.s b/sys/i386/isa/vector.s new file mode 100644 index 000000000000..38ac79cdb347 --- /dev/null +++ b/sys/i386/isa/vector.s @@ -0,0 +1,376 @@ +/* vector.s */ +/* + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00167 + * -------------------- ----- ---------------------- + * + * 04 Jun 93 Bruce Evans Fixed irq_num vs id_num for multiple + * devices configed on the same irq with + * respect to ipending. + * + */ + +#include "i386/isa/icu.h" +#include "i386/isa/isa.h" +#include "vector.h" + +#define ICU_EOI 0x20 /* XXX - define elsewhere */ + +#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8)) +#define IRQ_BYTE(irq_num) ((irq_num) / 8) + +#define ENABLE_ICU1 \ + movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ + FASTER_NOP ; /* ... ASAP ... */ \ + outb %al,$IO_ICU1 /* ... to clear in service bit */ +#ifdef AUTO_EOI_1 +#undef ENABLE_ICU1 /* we now use auto-EOI to reduce i/o */ +#define ENABLE_ICU1 +#endif + +#define ENABLE_ICU1_AND_2 \ + movb $ICU_EOI,%al ; /* as above */ \ + FASTER_NOP ; \ + outb %al,$IO_ICU2 ; /* but do second icu first */ \ + FASTER_NOP ; \ + outb %al,$IO_ICU1 /* then first icu */ +#ifdef AUTO_EOI_2 +#undef ENABLE_ICU1_AND_2 /* data sheet says no auto-EOI on slave ... */ +#define ENABLE_ICU1_AND_2 /* ... but it works */ +#endif + +/* + * Macros for interrupt interrupt entry, call to handler, and exit. + * + * XXX - the interrupt frame is set up to look like a trap frame. This is + * usually a waste of time. The only interrupt handlers that want a frame + * are the clock handler (it wants a clock frame), the npx handler (it's + * easier to do right all in assembler). The interrupt return routine + * needs a trap frame for rare AST's (it could easily convert the frame). + * The direct costs of setting up a trap frame are two pushl's (error + * code and trap number), an addl to get rid of these, and pushing and + * popping the call-saved regs %esi, %edi and %ebp twice, The indirect + * costs are making the driver interface nonuniform so unpending of + * interrupts is more complicated and slower (call_driver(unit) would + * be easier than ensuring an interrupt frame for all handlers. Finally, + * there are some struct copies in the npx handler and maybe in the clock + * handler that could be avoided by working more with pointers to frames + * instead of frames. + * + * XXX - should we do a cld on every system entry to avoid the requirement + * for scattered cld's? + * + * Coding notes for *.s: + * + * If possible, avoid operations that involve an operand size override. + * Word-sized operations might be smaller, but the operand size override + * makes them slower on on 486's and no faster on 386's unless perhaps + * the instruction pipeline is depleted. E.g., + * + * Use movl to seg regs instead of the equivalent but more descriptive + * movw - gas generates an irelevant (slower) operand size override. + * + * Use movl to ordinary regs in preference to movw and especially + * in preference to movz[bw]l. Use unsigned (long) variables with the + * top bits clear instead of unsigned short variables to provide more + * opportunities for movl. + * + * If possible, use byte-sized operations. They are smaller and no slower. + * + * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter. + * + * If the interrupt frame is made more flexible, INTR can push %eax first + * and decide the ipending case with less overhead, e.g., by avoiding + * loading segregs. + */ + +#define FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \ + pushl %eax ; /* save only call-used registers */ \ + pushl %ecx ; \ + pushl %edx ; \ + pushl %ds ; \ + /* pushl %es ; know compiler doesn't do string insns */ \ + movl $KDSEL,%eax ; \ + movl %ax,%ds ; \ + /* movl %ax,%es ; */ \ + SHOW_CLI ; /* although it interferes with "ASAP" */ \ + pushl $unit ; \ + call handler ; /* do the work ASAP */ \ + enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \ + addl $4,%esp ; \ + incl _cnt+V_INTR ; /* book-keeping can wait */ \ + COUNT_EVENT(_intrcnt_actv, id_num) ; \ + SHOW_STI ; \ + /* popl %es ; */ \ + popl %ds ; \ + popl %edx; \ + popl %ecx; \ + popl %eax; \ + iret + +#define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \ + pushl $0 ; /* dummy error code */ \ + pushl $T_ASTFLT ; \ + pushal ; \ + pushl %ds ; /* save our data and extra segments ... */ \ + pushl %es ; \ + movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \ + movl %ax,%ds ; /* ... early in case SHOW_A_LOT is on */ \ + movl %ax,%es ; \ + SHOW_CLI ; /* interrupt did an implicit cli */ \ + movb _imen + IRQ_BYTE(irq_num),%al ; \ + orb $IRQ_BIT(irq_num),%al ; \ + movb %al,_imen + IRQ_BYTE(irq_num) ; \ + SHOW_IMEN ; \ + FASTER_NOP ; \ + outb %al,$icu+1 ; \ + enable_icus ; \ + incl _cnt+V_INTR ; /* tally interrupts */ \ + movl _cpl,%eax ; \ + testb $IRQ_BIT(irq_num),%reg ; \ + jne 2f ; \ +1: ; \ + COUNT_EVENT(_intrcnt_actv, id_num) ; \ + movl _cpl,%eax ; \ + pushl %eax ; \ + pushl $unit ; \ + orl mask,%eax ; \ + movl %eax,_cpl ; \ + SHOW_CPL ; \ + SHOW_STI ; \ + sti ; \ + call handler ; \ + movb _imen + IRQ_BYTE(irq_num),%al ; \ + andb $~IRQ_BIT(irq_num),%al ; \ + movb %al,_imen + IRQ_BYTE(irq_num) ; \ + SHOW_IMEN ; \ + FASTER_NOP ; \ + outb %al,$icu+1 ; \ + jmp doreti ; \ +; \ + ALIGN_TEXT ; \ +2: ; \ + COUNT_EVENT(_intrcnt_pend, id_num) ; \ + movl $1b,%eax ; /* register resume address */ \ + /* XXX - someday do it at attach time */ \ + movl %eax,Vresume + (irq_num) * 4 ; \ + orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \ + SHOW_IPENDING ; \ + popl %es ; \ + popl %ds ; \ + popal ; \ + addl $4+4,%esp ; \ + iret + +/* + * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info + * about vectors, including a submacro 'BUILD_VECTOR' that operates on the + * info about each vector. We redefine 'BUILD_VECTOR' to expand the info + * in different ways. Here we expand it to a list of interrupt handlers. + * This order is of course unimportant. Elsewhere we expand it to inline + * linear search code for which the order is a little more important and + * concatenating the code with no holes is very important. + * + * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR. + * + * The info consists of the following items for each vector: + * + * name (identifier): name of the vector; used to build labels + * unit (expression): unit number to call the device driver with + * irq_num (number): number of the IRQ to handled (0-15) + * id_num (number): uniq numeric id for handler (assigned by config) + * mask (blank-ident): priority mask used + * handler (blank-ident): interrupt handler to call + * icu_num (number): (1 + irq_num / 8) converted for label building + * icu_enables (number): 1 for icu_num == 1, 1_AND_2 for icu_num == 2 + * reg (blank-ident): al for icu_num == 1, ah for icu_num == 2 + * + * 'irq_num' is converted in several ways at config time to get around + * limitations in cpp. The macros have blanks after commas iff they would + * not mess up identifiers and numbers. + */ + +#undef BUILD_FAST_VECTOR +#define BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \ + icu_num, icu_enables, reg) \ + .globl handler ; \ + .text ; \ + .globl _V/**/name ; \ + SUPERALIGN_TEXT ; \ +_V/**/name: ; \ + FAST_INTR(unit, irq_num, id_num, handler, ENABLE_ICU/**/icu_enables) + +#undef BUILD_VECTOR +#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ + icu_num, icu_enables, reg) \ + .globl handler ; \ + .text ; \ + .globl _V/**/name ; \ + SUPERALIGN_TEXT ; \ +_V/**/name: ; \ + INTR(unit,irq_num,id_num, mask, handler, IO_ICU/**/icu_num, \ + ENABLE_ICU/**/icu_enables, reg,) + + BUILD_VECTORS + + /* hardware interrupt catcher (IDT 32 - 47) */ + .globl _isa_strayintr + +#define STRAYINTR(irq_num, icu_num, icu_enables, reg) \ +IDTVEC(intr/**/irq_num) ; \ + INTR(irq_num,irq_num,irq_num, _highmask, _isa_strayintr, \ + IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray) + +/* + * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead + * of the mask IRQ2 (defined as IRQ9 == (1 << 9)). But IRQ 2 "can't happen". + * In fact, all stray interrupts "can't happen" except for bugs. The + * "stray" IRQ 7 is documented behaviour of the 8259. It happens when there + * is a glitch on any of its interrupt inputs. Does it really interrupt when + * IRQ 7 is masked? + * + * XXX - unpend doesn't work for these, it sends them to the real handler. + * + * XXX - the race bug during initialization may be because I changed the + * order of switching from the stray to the real interrupt handler to before + * enabling interrupts. The old order looked unsafe but maybe it is OK with + * the stray interrupt handler installed. But these handlers only reduce + * the window of vulnerability - it is still open at the end of + * isa_configure(). + * + * XXX - many comments are stale. + */ + + STRAYINTR(0,1,1, al) + STRAYINTR(1,1,1, al) + STRAYINTR(2,1,1, al) + STRAYINTR(3,1,1, al) + STRAYINTR(4,1,1, al) + STRAYINTR(5,1,1, al) + STRAYINTR(6,1,1, al) + STRAYINTR(8,2,1_AND_2, ah) + STRAYINTR(9,2,1_AND_2, ah) + STRAYINTR(10,2,1_AND_2, ah) + STRAYINTR(11,2,1_AND_2, ah) + STRAYINTR(12,2,1_AND_2, ah) + STRAYINTR(13,2,1_AND_2, ah) + STRAYINTR(14,2,1_AND_2, ah) + STRAYINTR(15,2,1_AND_2, ah) +IDTVEC(intrdefault) + STRAYINTR(7,1,1, al) /* XXX */ +#if 0 + INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2 +#endif +/* + * These are the interrupt counters, I moved them here from icu.s so that + * they are with the name table. rgrimes + * + * There are now lots of counters, this has been redone to work with + * Bruce Evans intr-0.1 code, which I modified some more to make it all + * work with vmstat. + */ + .data +Vresume: .space 16 * 4 /* where to resume intr handler after unpend */ + .globl _intrcnt +_intrcnt: /* used by vmstat to calc size of table */ + .globl _intrcnt_bad7 +_intrcnt_bad7: .space 4 /* glitches on irq 7 */ + .globl _intrcnt_bad15 +_intrcnt_bad15: .space 4 /* glitches on irq 15 */ + .globl _intrcnt_stray +_intrcnt_stray: .space 4 /* total count of stray interrupts */ + .globl _intrcnt_actv +_intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */ + .globl _intrcnt_pend +_intrcnt_pend: .space NR_REAL_INT_HANDLERS * 4 /* pending interrupts */ + .globl _intrcnt_spl +_intrcnt_spl: .space 32 * 4 /* XXX 32 should not be hard coded ? */ + .globl _intrcnt_show +_intrcnt_show: .space 8 * 4 /* XXX 16 should not be hard coded ? */ + .globl _eintrcnt +_eintrcnt: /* used by vmstat to calc size of table */ + +/* + * Build the interrupt name table for vmstat + */ + +#undef BUILD_FAST_VECTOR +#define BUILD_FAST_VECTOR BUILD_VECTOR + +#undef BUILD_VECTOR +#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ + icu_num, icu_enables, reg) \ + .ascii "name irq" ; \ + .asciz "irq_num" +/* + * XXX - use the STRING and CONCAT macros from <sys/cdefs.h> to stringize + * and concatenate names above and elsewhere. + */ + + .text + .globl _intrnames, _eintrnames +_intrnames: + BUILD_VECTOR(bad,,7,,,,,,) + BUILD_VECTOR(bad,,15,,,,,,) + BUILD_VECTOR(stray,,,,,,,,) + BUILD_VECTORS + +#undef BUILD_FAST_VECTOR +#define BUILD_FAST_VECTOR BUILD_VECTOR + +#undef BUILD_VECTOR +#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ + icu_num, icu_enables, reg) \ + .asciz "name pend" + + BUILD_VECTORS + +/* + * now the spl names + */ + .asciz "unpend_v" + .asciz "doreti" + .asciz "p0!ni" + .asciz "!p0!ni" + .asciz "p0ni" + .asciz "netisr_raw" + .asciz "netisr_ip" + .asciz "netisr_imp" + .asciz "netisr_ns" + .asciz "softclock" + .asciz "trap" + .asciz "doreti_exit2" + .asciz "splbio" + .asciz "splclock" + .asciz "splhigh" + .asciz "splimp" + .asciz "splnet" + .asciz "splsoftclock" + .asciz "spltty" + .asciz "spl0" + .asciz "netisr_raw2" + .asciz "netisr_ip2" + .asciz "splx" + .asciz "splx!0" + .asciz "unpend_V" + .asciz "spl25" /* spl25-spl31 are spares */ + .asciz "spl26" + .asciz "spl27" + .asciz "spl28" + .asciz "spl29" + .asciz "spl30" + .asciz "spl31" +/* + * now the mask names + */ + .asciz "cli" + .asciz "cpl" + .asciz "imen" + .asciz "ipending" + .asciz "sti" + .asciz "mask5" /* mask5-mask7 are spares */ + .asciz "mask6" + .asciz "mask7" + +_eintrnames: diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c new file mode 100644 index 000000000000..bbec45b5696c --- /dev/null +++ b/sys/i386/isa/wd.c @@ -0,0 +1,1352 @@ +/*- + * 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. + * + * from:@(#)wd.c 7.2 (Berkeley) 5/9/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 6 00155 + * -------------------- ----- ---------------------- + * + * 17 Sep 92 Frank Maclachlan Fixed I/O error reporting on raw device + * 31 Jul 92 Christoph Robitschko Fixed second disk recognition, + * bzero of malloced memory for warm + * boot problem. + * 19 Aug 92 Frank Maclachlan Fixed bug when first sector of a + * multisector read is in bad144 table. + * 17 Jan 93 B. Evans & A.Chernov Fixed bugs from previous patches, + * driver initialization, and cylinder + * boundary conditions. + * 28 Mar 93 Charles Hannum Add missing splx calls. + * 20 Apr 93 Terry Lee Always report disk errors + * 20 Apr 93 Brett Lymn Change infinite while loops to + * timeouts + * 17 May 93 Rodney W. Grimes Fixed all 1000000 to use WDCTIMEOUT, + * and increased to 1000000*10 for new + * intr-0.1 code. + */ + +/* TODO:peel out buffer at low ipl, speed improvement */ + + +#include "wd.h" +#if NWD > 0 + +#include "param.h" +#include "dkbad.h" +#include "systm.h" +#include "conf.h" +#include "file.h" +#include "stat.h" +#include "ioctl.h" +#include "disklabel.h" +#include "buf.h" +#include "uio.h" +#include "malloc.h" +#include "machine/cpu.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/icu.h" +#include "i386/isa/wdreg.h" +#include "syslog.h" +#include "vm/vm.h" + +#define _NWD (NWD - 1) /* One is for the controller XXX 31 Jul 92*/ + +#ifndef WDCTIMEOUT +#define WDCTIMEOUT 10000000 /* arbitrary timeout for drive ready waits */ +#endif + +#define RETRIES 5 /* number of retries before giving up */ +#define MAXTRANSFER 32 /* max size of transfer in page clusters */ + +#define wdnoreloc(dev) (minor(dev) & 0x80) /* ignore partition table */ +#define wddospart(dev) (minor(dev) & 0x40) /* use dos partitions */ +#define wdunit(dev) ((minor(dev) & 0x38) >> 3) +#define wdpart(dev) (minor(dev) & 0x7) +#define makewddev(maj, unit, part) (makedev(maj,((unit<<3)+part))) +#define WDRAW 3 /* 'd' partition isn't a partition! */ + +#define b_cylin b_resid /* cylinder number for doing IO to */ + /* shares an entry in the buf struct */ + +/* + * Drive states. Used to initialize drive. + */ + +#define CLOSED 0 /* disk is closed. */ +#define WANTOPEN 1 /* open requested, not started */ +#define RECAL 2 /* doing restore */ +#define OPEN 3 /* done with open */ + +/* + * The structure of a disk drive. + */ +struct disk { + long dk_bc; /* byte count left */ + short dk_skip; /* blocks already transferred */ + char dk_unit; /* physical unit number */ + char dk_state; /* control state */ + u_char dk_status; /* copy of status reg. */ + u_char dk_error; /* copy of error reg. */ + short dk_port; /* i/o port base */ + + u_long dk_copenpart; /* character units open on this drive */ + u_long dk_bopenpart; /* block units open on this drive */ + u_long dk_openpart; /* all units open on this drive */ + short dk_wlabel; /* label writable? */ + short dk_flags; /* drive characteistics found */ +#define DKFL_DOSPART 0x00001 /* has DOS partition table */ +#define DKFL_QUIET 0x00002 /* report errors back, but don't complain */ +#define DKFL_SINGLE 0x00004 /* sector at a time mode */ +#define DKFL_ERROR 0x00008 /* processing a disk error */ +#define DKFL_BSDLABEL 0x00010 /* has a BSD disk label */ +#define DKFL_BADSECT 0x00020 /* has a bad144 badsector table */ +#define DKFL_WRITEPROT 0x00040 /* manual unit write protect */ + struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */ + struct disklabel dk_dd; /* device configuration data */ + struct dos_partition + dk_dospartitions[NDOSPART]; /* DOS view of disk */ + struct dkbad dk_bad; /* bad sector table */ +}; + +struct disk *wddrives[_NWD]; /* table of units */ +struct buf wdtab; +struct buf wdutab[_NWD]; /* head of queue per drive */ +struct buf rwdbuf[_NWD]; /* buffers for raw IO */ +long wdxfer[_NWD]; /* count of transfers */ +#ifdef WDDEBUG +int wddebug; +#endif + +struct isa_driver wddriver = { + wdprobe, wdattach, "wd", +}; + +void wdustart(struct disk *); +void wdstart(); +int wdcommand(struct disk *, int); +int wdcontrol(struct buf *); +int wdsetctlr(dev_t, struct disk *); +int wdgetctlr(int, struct disk *); + +/* + * Probe for controller. + */ +int +wdprobe(struct isa_device *dvp) +{ + int unit = dvp->id_unit; + struct disk *du; + int wdc; + + if (unit >= _NWD) /* 31 Jul 92*/ + return(0); + + if ((du = wddrives[unit]) == 0) { + du = wddrives[unit] = (struct disk *) + malloc (sizeof(struct disk), M_TEMP, M_NOWAIT); + bzero (du, sizeof(struct disk)); /* 31 Jul 92*/ + du->dk_unit = unit; + } + + wdc = du->dk_port = dvp->id_iobase; + + /* check if we have registers that work */ + outb(wdc+wd_cyl_lo, 0xa5) ; /* wd_cyl_lo is read/write */ + if(inb(wdc+wd_cyl_lo) != 0xa5) + goto nodevice; + + /* reset the device */ + outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS)); + DELAY(1000); + outb(wdc+wd_ctlr, WDCTL_IDS); + DELAY(1000); + + /* execute a controller only command */ + if (wdcommand(du, WDCC_DIAGNOSE) < 0) + goto nodevice; + + (void) inb(wdc+wd_error); /* XXX! */ + outb(wdc+wd_ctlr, WDCTL_4BIT); + return (1); + +nodevice: + free(du, M_TEMP); + wddrives[unit] = 0; + return (0); +} + +/* + * Attach each drive if possible. + */ +int +wdattach(struct isa_device *dvp) +{ + int unit; +/* int unit = dvp->id_unit;*/ + + for (unit=0; unit< _NWD; unit++) { + struct disk *du; + if ((du = wddrives[unit]) == 0) { + du = wddrives[unit] = (struct disk *) + malloc (sizeof(struct disk), M_TEMP, M_NOWAIT); + bzero (du, sizeof(struct disk)); + du->dk_unit = unit; + du->dk_port = dvp->id_iobase; + } + + /* print out description of drive, suppressing multiple blanks*/ + if(wdgetctlr(unit, du) == 0) { + int i, blank; + char c; + printf(" %d:<", unit); + for (i = blank = 0 ; i < sizeof(du->dk_params.wdp_model); i++) { + char c = du->dk_params.wdp_model[i]; + + if (blank && c == ' ') continue; + if (blank && c != ' ') { + printf(" %c", c); + blank = 0; + continue; + } + if (c == ' ') + blank = 1; + else + printf("%c", c); + } + printf(">"); + du->dk_unit = unit; + } + else { + /* old ST506 controller */ + printf(" %d:<wdgetctlr failed, assuming OK>", + unit); + } + } + return(1); +} + +/* Read/write routine for a buffer. Finds the proper unit, range checks + * arguments, and schedules the transfer. Does not wait for the transfer + * to complete. Multi-page transfers are supported. All I/O requests must + * be a multiple of a sector in length. + */ +int +wdstrategy(register struct buf *bp) +{ + register struct buf *dp; + struct disklabel *lp; + register struct partition *p; + struct disk *du; /* Disk unit to do the IO. */ + long maxsz, sz; + int unit = wdunit(bp->b_dev); + int s; + + /* valid unit, controller, and request? */ + if (unit >= _NWD || bp->b_blkno < 0 || (du = wddrives[unit]) == 0) { + + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR; + goto done; + } + + /* "soft" write protect check */ + if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) { + bp->b_error = EROFS; + bp->b_flags |= B_ERROR; + goto done; + } + + /* have partitions and want to use them? */ + if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) { + + /* + * do bounds checking, adjust transfer. if error, process. + * if end of partition, just return + */ + if (bounds_check_with_label(bp, &du->dk_dd, du->dk_wlabel) <= 0) + goto done; + /* otherwise, process transfer request */ + } + +q: + /* queue transfer on drive, activate drive and controller if idle */ + dp = &wdutab[unit]; + s = splbio(); + disksort(dp, bp); + if (dp->b_active == 0) + wdustart(du); /* start drive */ + if (wdtab.b_active == 0) + wdstart(s); /* start controller */ + splx(s); + return; + +done: + /* toss transfer, we're done early */ + biodone(bp); +} + +/* + * Routine to queue a command to the controller. The unit's + * request is linked into the active list for the controller. + * If the controller is idle, the transfer is started. + */ +static void +wdustart(register struct disk *du) +{ + register struct buf *bp, *dp = &wdutab[du->dk_unit]; + + /* unit already active? */ + if (dp->b_active) + return; + + /* anything to start? */ + bp = dp->b_actf; + if (bp == NULL) + return; + + /* link onto controller queue */ + dp->b_forw = NULL; + if (wdtab.b_actf == NULL) + wdtab.b_actf = dp; + else + wdtab.b_actl->b_forw = dp; + wdtab.b_actl = dp; + + /* mark the drive unit as busy */ + dp->b_active = 1; +} + +/* + * Controller startup routine. This does the calculation, and starts + * a single-sector read or write operation. Called to start a transfer, + * or from the interrupt routine to continue a multi-sector transfer. + * RESTRICTIONS: + * 1. The transfer length must be an exact multiple of the sector size. + */ + +static void +wdstart() +{ + register struct disk *du; /* disk unit for IO */ + register struct buf *bp; + struct disklabel *lp; + struct buf *dp; + register struct bt_bad *bt_ptr; + long blknum, pagcnt, cylin, head, sector; + long secpertrk, secpercyl, addr, i, timeout; + int unit, s, wdc; + +loop: + /* is there a drive for the controller to do a transfer with? */ + dp = wdtab.b_actf; + if (dp == NULL) + return; + + /* is there a transfer to this drive ? if so, link it on + the controller's queue */ + bp = dp->b_actf; + if (bp == NULL) { + wdtab.b_actf = dp->b_forw; + goto loop; + } + + /* obtain controller and drive information */ + unit = wdunit(bp->b_dev); + du = wddrives[unit]; + + /* if not really a transfer, do control operations specially */ + if (du->dk_state < OPEN) { + (void) wdcontrol(bp); + return; + } + + /* calculate transfer details */ + blknum = bp->b_blkno + du->dk_skip; +/*if(wddebug)printf("bn%d ", blknum);*/ +#ifdef WDDEBUG + if (du->dk_skip == 0) + printf("\nwdstart %d: %s %d@%d; map ", unit, + (bp->b_flags & B_READ) ? "read" : "write", + bp->b_bcount, blknum); + else + printf(" %d)%x", du->dk_skip, inb(wdc+wd_altsts)); +#endif + addr = (int) bp->b_un.b_addr; + if (du->dk_skip == 0) + du->dk_bc = bp->b_bcount; + + lp = &du->dk_dd; + secpertrk = lp->d_nsectors; + secpercyl = lp->d_secpercyl; + if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) + blknum += lp->d_partitions[wdpart(bp->b_dev)].p_offset; + cylin = blknum / secpercyl; + head = (blknum % secpercyl) / secpertrk; + sector = blknum % secpertrk; + + /* + * See if the current block is in the bad block list. + * (If we have one, and not formatting.) + */ + if ((du->dk_flags & (DKFL_SINGLE|DKFL_BADSECT)) /* 19 Aug 92*/ + == (DKFL_SINGLE|DKFL_BADSECT)) + for (bt_ptr = du->dk_bad.bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) { + if (bt_ptr->bt_cyl > cylin) + /* Sorted list, and we passed our cylinder. quit. */ + break; + if (bt_ptr->bt_cyl == cylin && + bt_ptr->bt_trksec == (head << 8) + sector) { + /* + * Found bad block. Calculate new block addr. + * This starts at the end of the disk (skip the + * last track which is used for the bad block list), + * and works backwards to the front of the disk. + */ +#ifdef WDDEBUG + printf("--- badblock code -> Old = %d; ", + blknum); +#endif + blknum = lp->d_secperunit - lp->d_nsectors + - (bt_ptr - du->dk_bad.bt_bad) - 1; + cylin = blknum / secpercyl; + head = (blknum % secpercyl) / secpertrk; + sector = blknum % secpertrk; +#ifdef WDDEBUG + printf("new = %d\n", blknum); +#endif + break; + } + } +/*if(wddebug)pg("c%d h%d s%d ", cylin, head, sector);*/ + sector += 1; /* sectors begin with 1, not 0 */ + + wdtab.b_active = 1; /* mark controller active */ + wdc = du->dk_port; + +RETRY: + /* if starting a multisector transfer, or doing single transfers */ + if (du->dk_skip == 0 || (du->dk_flags & DKFL_SINGLE)) { + if (wdtab.b_errcnt && (bp->b_flags & B_READ) == 0) + du->dk_bc += DEV_BSIZE; + + /* controller idle? */ + timeout = 0; + while (inb(wdc+wd_status) & WDCS_BUSY) + { + if (++timeout > WDCTIMEOUT) + { + printf("wd.c: Controller busy too long!\n"); + /* reset the device */ + outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS)); + DELAY(1000); + outb(wdc+wd_ctlr, WDCTL_IDS); + DELAY(1000); + (void) inb(wdc+wd_error); /* XXX! */ + outb(wdc+wd_ctlr, WDCTL_4BIT); + break; + } + } + + /* stuff the task file */ + outb(wdc+wd_precomp, lp->d_precompcyl / 4); +#ifdef B_FORMAT + if (bp->b_flags & B_FORMAT) { + outb(wdc+wd_sector, lp->d_gap3); + outb(wdc+wd_seccnt, lp->d_nsectors); + } else { +#endif + if (du->dk_flags & DKFL_SINGLE) + outb(wdc+wd_seccnt, 1); + else + outb(wdc+wd_seccnt, howmany(du->dk_bc, DEV_BSIZE)); + outb(wdc+wd_sector, sector); + +#ifdef B_FORMAT + } +#endif + + outb(wdc+wd_cyl_lo, cylin); + outb(wdc+wd_cyl_hi, cylin >> 8); + + /* set up the SDH register (select drive) */ + outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf)); + + /* wait for drive to become ready */ + timeout = 0; + while ((inb(wdc+wd_status) & WDCS_READY) == 0) + { + if (++timeout > WDCTIMEOUT) + { + printf("wd.c: Drive busy too long!\n"); + /* reset the device */ + outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS)); + DELAY(1000); + outb(wdc+wd_ctlr, WDCTL_IDS); + DELAY(1000); + (void) inb(wdc+wd_error); /* XXX! */ + outb(wdc+wd_ctlr, WDCTL_4BIT); + goto RETRY; + } + } + + /* initiate command! */ +#ifdef B_FORMAT + if (bp->b_flags & B_FORMAT) + outb(wdc+wd_command, WDCC_FORMAT); + else +#endif + outb(wdc+wd_command, + (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE); +#ifdef WDDEBUG + printf("sector %d cylin %d head %d addr %x sts %x\n", + sector, cylin, head, addr, inb(wdc+wd_altsts)); +#endif + } + + /* if this is a read operation, just go away until it's done. */ + if (bp->b_flags & B_READ) return; + + /* ready to send data? */ + timeout = 0; + while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) + { + if (++timeout > WDCTIMEOUT) + { + printf("wd.c: Drive not ready for too long!\n"); + /* reset the device */ + outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS)); + DELAY(1000); + outb(wdc+wd_ctlr, WDCTL_IDS); + DELAY(1000); + (void) inb(wdc+wd_error); /* XXX! */ + outb(wdc+wd_ctlr, WDCTL_4BIT); + goto RETRY; + } + } + + /* then send it! */ + outsw (wdc+wd_data, addr+du->dk_skip * DEV_BSIZE, + DEV_BSIZE/sizeof(short)); + du->dk_bc -= DEV_BSIZE; +} + +/* Interrupt routine for the controller. Acknowledge the interrupt, check for + * errors on the current operation, mark it done if necessary, and start + * the next request. Also check for a partially done transfer, and + * continue with the next chunk if so. + */ +void +wdintr(struct intrframe wdif) +{ + register struct disk *du; + register struct buf *bp, *dp; + int status, wdc; + char partch ; + + if (!wdtab.b_active) { +#ifdef nyet + printf("wd: extra interrupt\n"); +#endif + return; + } + + dp = wdtab.b_actf; + bp = dp->b_actf; + du = wddrives[wdunit(bp->b_dev)]; + wdc = du->dk_port; + +#ifdef WDDEBUG + printf("I "); +#endif + + while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ; + + /* is it not a transfer, but a control operation? */ + if (du->dk_state < OPEN) { + if (wdcontrol(bp)) + wdstart(); + return; + } + + /* have we an error? */ + if (status & (WDCS_ERR | WDCS_ECCCOR)) { + + du->dk_status = status; + du->dk_error = inb(wdc + wd_error); +#ifdef WDDEBUG + printf("status %x error %x\n", status, du->dk_error); +#endif + if((du->dk_flags & DKFL_SINGLE) == 0) { + du->dk_flags |= DKFL_ERROR; + goto outt; + } +#ifdef B_FORMAT + if (bp->b_flags & B_FORMAT) { + bp->b_error = EIO; /* 17 Sep 92*/ + bp->b_flags |= B_ERROR; + goto done; + } +#endif + + /* error or error correction? */ + if (status & WDCS_ERR) { + if (++wdtab.b_errcnt < RETRIES) { + wdtab.b_active = 0; + } else { + if((du->dk_flags&DKFL_QUIET) == 0) { + diskerr(bp, "wd", "hard error", + LOG_PRINTF, du->dk_skip, + &du->dk_dd); +#ifdef WDDEBUG + printf( "status %b error %b\n", + status, WDCS_BITS, + inb(wdc+wd_error), WDERR_BITS); +#endif + } + bp->b_error = EIO; /* 17 Sep 92*/ + bp->b_flags |= B_ERROR; /* flag the error */ + } + } else if((du->dk_flags&DKFL_QUIET) == 0) { + diskerr(bp, "wd", "soft ecc", 0, + du->dk_skip, &du->dk_dd); + } + } +outt: + + /* + * If this was a successful read operation, fetch the data. + */ + if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) { + int chk, dummy; + + chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short)); + + /* ready to receive data? */ + while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) + ; + + /* suck in data */ + insw (wdc+wd_data, + (int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk); + du->dk_bc -= chk * sizeof(short); + + /* for obselete fractional sector reads */ + while (chk++ < 256) insw (wdc+wd_data, &dummy, 1); + } + + wdxfer[du->dk_unit]++; + if (wdtab.b_active) { + if ((bp->b_flags & B_ERROR) == 0) { + du->dk_skip++; /* Add to successful sectors. */ + if (wdtab.b_errcnt && (du->dk_flags & DKFL_QUIET) == 0) + diskerr(bp, "wd", "soft error", 0, + du->dk_skip, &du->dk_dd); + wdtab.b_errcnt = 0; + + /* see if more to transfer */ + if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) { + wdstart(); + return; /* next chunk is started */ + } else if ((du->dk_flags & (DKFL_SINGLE|DKFL_ERROR)) + == DKFL_ERROR) { + du->dk_skip = 0; + du->dk_flags &= ~DKFL_ERROR; + du->dk_flags |= DKFL_SINGLE; + wdstart(); + return; /* redo xfer sector by sector */ + } + } + +done: + /* done with this transfer, with or without error */ + du->dk_flags &= ~DKFL_SINGLE; + wdtab.b_actf = dp->b_forw; + wdtab.b_errcnt = 0; + du->dk_skip = 0; + dp->b_active = 0; + dp->b_actf = bp->av_forw; + dp->b_errcnt = 0; + bp->b_resid = 0; + biodone(bp); + } + + /* controller idle */ + wdtab.b_active = 0; + + /* anything more on drive queue? */ + if (dp->b_actf) + wdustart(du); + /* anything more for controller to do? */ + if (wdtab.b_actf) + wdstart(); +} + +/* + * Initialize a drive. + */ +int +wdopen(dev_t dev, int flags, int fmt, struct proc *p) +{ + register unsigned int unit; + register struct disk *du; + int part = wdpart(dev), mask = 1 << part; + struct partition *pp; + struct dkbad *db; + int i, error = 0; + char *msg; + + unit = wdunit(dev); + if (unit >= _NWD) return (ENXIO) ; + + du = wddrives[unit]; + if (du == 0) return (ENXIO) ; + + if ((du->dk_flags & DKFL_BSDLABEL) == 0) { + du->dk_flags |= DKFL_WRITEPROT; + wdutab[unit].b_actf = NULL; + + /* + * Use the default sizes until we've read the label, + * or longer if there isn't one there. + */ + bzero(&du->dk_dd, sizeof(du->dk_dd)); +#undef d_type /* fix goddamn segments.h! XXX */ + du->dk_dd.d_type = DTYPE_ST506; + du->dk_dd.d_ncylinders = 1024; + du->dk_dd.d_secsize = DEV_BSIZE; + du->dk_dd.d_ntracks = 8; + du->dk_dd.d_nsectors = 17; + du->dk_dd.d_secpercyl = 17*8; + du->dk_state = WANTOPEN; + du->dk_unit = unit; + du->dk_flags &= ~DKFL_QUIET; + + /* read label using "c" partition */ + if (msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW), + wdstrategy, &du->dk_dd, du->dk_dospartitions, + &du->dk_bad, 0)) { + if((du->dk_flags&DKFL_QUIET) == 0) { + log(LOG_WARNING, "wd%d: cannot find label (%s)\n", + unit, msg); + error = EINVAL; /* XXX needs translation */ + } + goto done; + } else { + + wdsetctlr(dev, du); + du->dk_flags |= DKFL_BSDLABEL; + du->dk_flags &= ~DKFL_WRITEPROT; + if (du->dk_dd.d_flags & D_BADSECT) + du->dk_flags |= DKFL_BADSECT; + } + +done: + if (error) + return(error); + + } + /* + * Warn if a partion is opened + * that overlaps another partition which is open + * unless one is the "raw" partition (whole disk). + */ + if ((du->dk_openpart & mask) == 0 /*&& part != RAWPART*/ && part != WDRAW) { + int start, end; + + pp = &du->dk_dd.d_partitions[part]; + start = pp->p_offset; + end = pp->p_offset + pp->p_size; + for (pp = du->dk_dd.d_partitions; + pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions]; + pp++) { + if (pp->p_offset + pp->p_size <= start || + pp->p_offset >= end) + continue; + /*if (pp - du->dk_dd.d_partitions == RAWPART) + continue; */ + if (pp - du->dk_dd.d_partitions == WDRAW) + continue; + if (du->dk_openpart & (1 << (pp - + du->dk_dd.d_partitions))) + log(LOG_WARNING, + "wd%d%c: overlaps open partition (%c)\n", + unit, part + 'a', + pp - du->dk_dd.d_partitions + 'a'); + } + } + if (part >= du->dk_dd.d_npartitions && part != WDRAW) + return (ENXIO); + + /* insure only one open at a time */ + du->dk_openpart |= mask; + switch (fmt) { + case S_IFCHR: + du->dk_copenpart |= mask; + break; + case S_IFBLK: + du->dk_bopenpart |= mask; + break; + } + return (0); +} + +/* + * Implement operations other than read/write. + * Called from wdstart or wdintr during opens and formats. + * Uses finite-state-machine to track progress of operation in progress. + * Returns 0 if operation still in progress, 1 if completed. + */ +static int +wdcontrol(register struct buf *bp) +{ + register struct disk *du; + register unit; + unsigned char stat; + int s, cnt; + extern int bootdev; + int cyl, trk, sec, i, wdc; + struct wdparams foo; + + du = wddrives[wdunit(bp->b_dev)]; + unit = du->dk_unit; + wdc = du->dk_port; + + switch (du->dk_state) { + + tryagainrecal: + case WANTOPEN: /* set SDH, step rate, do restore */ +#ifdef WDDEBUG + printf("wd%d: recal ", unit); +#endif + s = splbio(); /* not called from intr level ... */ + wdgetctlr(unit, du); + + outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); + wdtab.b_active = 1; + + /* wait for drive and controller to become ready */ + for (i = WDCTIMEOUT; (inb(wdc+wd_status) & (WDCS_READY|WDCS_BUSY)) + != WDCS_READY && i-- != 0; ) + ; + outb(wdc+wd_command, WDCC_RESTORE | WD_STEP); + du->dk_state++; + splx(s); + return(0); + + case RECAL: + if ((stat = inb(wdc+wd_status)) & WDCS_ERR) { + if ((du->dk_flags & DKFL_QUIET) == 0) { + printf("wd%d: recal", du->dk_unit); + printf(": status %b error %b\n", + stat, WDCS_BITS, inb(wdc+wd_error), + WDERR_BITS); + } + if (++wdtab.b_errcnt < RETRIES) { + du->dk_state = WANTOPEN; + goto tryagainrecal; + } + bp->b_error = ENXIO; /* XXX needs translation */ + goto badopen; + } + + /* some controllers require this ... */ + wdsetctlr(bp->b_dev, du); + + wdtab.b_errcnt = 0; + du->dk_state = OPEN; + /* + * The rest of the initialization can be done + * by normal means. + */ + return(1); + + default: + panic("wdcontrol"); + } + /* NOTREACHED */ + +badopen: + if ((du->dk_flags & DKFL_QUIET) == 0) + printf(": status %b error %b\n", + stat, WDCS_BITS, inb(wdc + wd_error), WDERR_BITS); + bp->b_flags |= B_ERROR; + return(1); +} + +/* + * send a command and wait uninterruptibly until controller is finished. + * return -1 if controller busy for too long, otherwise + * return status. intended for brief controller commands at critical points. + * assumes interrupts are blocked. + */ +static int +wdcommand(struct disk *du, int cmd) { + int timeout = WDCTIMEOUT, stat, wdc; + + /* controller ready for command? */ + wdc = du->dk_port; + while (((stat = inb(wdc + wd_status)) & WDCS_BUSY) && timeout > 0) + timeout--; + if (timeout <= 0) + return(-1); + + /* send command, await results */ + outb(wdc+wd_command, cmd); + while (((stat = inb(wdc+wd_status)) & WDCS_BUSY) && timeout > 0) + timeout--; + if (timeout <= 0) + return(-1); + if (cmd != WDCC_READP) + return (stat); + + /* is controller ready to return data? */ + while (((stat = inb(wdc+wd_status)) & (WDCS_ERR|WDCS_DRQ)) == 0 && + timeout > 0) + timeout--; + if (timeout <= 0) + return(-1); + + return (stat); +} + +/* + * issue IDC to drive to tell it just what geometry it is to be. + */ +static int +wdsetctlr(dev_t dev, struct disk *du) { + int stat, x, wdc; + +/*printf("C%dH%dS%d ", du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, + du->dk_dd.d_nsectors);*/ + + x = splbio(); + wdc = du->dk_port; + outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders+1); + outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders+1)>>8); + outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1); + outb(wdc+wd_seccnt, du->dk_dd.d_nsectors); + stat = wdcommand(du, WDCC_IDC); + + if (stat < 0) { + splx(x); + return(stat); + } + if (stat & WDCS_ERR) + printf("wdsetctlr: status %b error %b\n", + stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS); + splx(x); + return(stat); +} + +/* + * issue READP to drive to ask it what it is. + */ +static int +wdgetctlr(int u, struct disk *du) { + int stat, x, i, wdc; + char tb[DEV_BSIZE]; + struct wdparams *wp; + + x = splbio(); /* not called from intr level ... */ + wdc = du->dk_port; + outb(wdc+wd_sdh, WDSD_IBM | (u << 4)); + stat = wdcommand(du, WDCC_READP); + + if (stat < 0) { + splx(x); + return(stat); + } + if (stat & WDCS_ERR) { + stat = inb(wdc+wd_error); + splx(x); + return(stat); + } + + /* obtain parameters */ + wp = &du->dk_params; + insw(wdc+wd_data, tb, sizeof(tb)/sizeof(short)); + bcopy(tb, wp, sizeof(struct wdparams)); + + /* shuffle string byte order */ + for (i=0; i < sizeof(wp->wdp_model) ;i+=2) { + u_short *p; + p = (u_short *) (wp->wdp_model + i); + *p = ntohs(*p); + } +/*printf("gc %x cyl %d trk %d sec %d type %d sz %d model %s\n", wp->wdp_config, +wp->wdp_fixedcyl+wp->wdp_removcyl, wp->wdp_heads, wp->wdp_sectors, +wp->wdp_cntype, wp->wdp_cnsbsz, wp->wdp_model);*/ + + /* update disklabel given drive information */ + du->dk_dd.d_ncylinders = wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/; + du->dk_dd.d_ntracks = wp->wdp_heads; + du->dk_dd.d_nsectors = wp->wdp_sectors; + du->dk_dd.d_secpercyl = du->dk_dd.d_ntracks * du->dk_dd.d_nsectors; + du->dk_dd.d_partitions[1].p_size = du->dk_dd.d_secpercyl * + wp->wdp_sectors; + du->dk_dd.d_partitions[1].p_offset = 0; + /* dubious ... */ + bcopy("ESDI/IDE", du->dk_dd.d_typename, 9); + bcopy(wp->wdp_model+20, du->dk_dd.d_packname, 14-1); + /* better ... */ + du->dk_dd.d_type = DTYPE_ESDI; + du->dk_dd.d_subtype |= DSTYPE_GEOMETRY; + + /* XXX sometimes possibly needed */ + (void) inb(wdc+wd_status); + return (0); +} + + +/* ARGSUSED */ +int +wdclose(dev_t dev, int flags, int fmt) +{ + register struct disk *du; + int part = wdpart(dev), mask = 1 << part; + + du = wddrives[wdunit(dev)]; + + /* insure only one open at a time */ + du->dk_openpart &= ~mask; + switch (fmt) { + case S_IFCHR: + du->dk_copenpart &= ~mask; + break; + case S_IFBLK: + du->dk_bopenpart &= ~mask; + break; + } + return(0); +} + +int +wdioctl(dev_t dev, int cmd, caddr_t addr, int flag) +{ + int unit = wdunit(dev); + register struct disk *du; + int error = 0; + struct uio auio; + struct iovec aiov; + + du = wddrives[unit]; + + switch (cmd) { + + case DIOCSBAD: + if ((flag & FWRITE) == 0) + error = EBADF; + else + du->dk_bad = *(struct dkbad *)addr; + break; + + case DIOCGDINFO: + *(struct disklabel *)addr = du->dk_dd; + break; + + case DIOCGPART: + ((struct partinfo *)addr)->disklab = &du->dk_dd; + ((struct partinfo *)addr)->part = + &du->dk_dd.d_partitions[wdpart(dev)]; + break; + + case DIOCSDINFO: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = setdisklabel(&du->dk_dd, + (struct disklabel *)addr, + /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart : */0, + du->dk_dospartitions); + if (error == 0) { + du->dk_flags |= DKFL_BSDLABEL; + wdsetctlr(dev, du); + } + break; + + case DIOCWLABEL: + du->dk_flags &= ~DKFL_WRITEPROT; + if ((flag & FWRITE) == 0) + error = EBADF; + else + du->dk_wlabel = *(int *)addr; + break; + + case DIOCWDINFO: + du->dk_flags &= ~DKFL_WRITEPROT; + if ((flag & FWRITE) == 0) + error = EBADF; + else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr, + /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart :*/ 0, + du->dk_dospartitions)) == 0) { + int wlab; + + du->dk_flags |= DKFL_BSDLABEL; + wdsetctlr(dev, du); + + /* simulate opening partition 0 so write succeeds */ + du->dk_openpart |= (1 << 0); /* XXX */ + wlab = du->dk_wlabel; + du->dk_wlabel = 1; + error = writedisklabel(dev, wdstrategy, + &du->dk_dd, du->dk_dospartitions); + du->dk_openpart = du->dk_copenpart | du->dk_bopenpart; + du->dk_wlabel = wlab; + } + break; + +#ifdef notyet + case DIOCGDINFOP: + *(struct disklabel **)addr = &(du->dk_dd); + break; + + case DIOCWFORMAT: + if ((flag & FWRITE) == 0) + error = EBADF; + else { + register struct format_op *fop; + + fop = (struct format_op *)addr; + aiov.iov_base = fop->df_buf; + aiov.iov_len = fop->df_count; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_resid = fop->df_count; + auio.uio_segflg = 0; + auio.uio_offset = + fop->df_startblk * du->dk_dd.d_secsize; + error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE, + minphys, &auio); + fop->df_count -= auio.uio_resid; + fop->df_reg[0] = du->dk_status; + fop->df_reg[1] = du->dk_error; + } + break; +#endif + + default: + error = ENOTTY; + break; + } + return (error); +} + +#ifdef B_FORMAT +int +wdformat(struct buf *bp) +{ + + bp->b_flags |= B_FORMAT; + return (wdstrategy(bp)); +} +#endif + +int +wdsize(dev_t dev) +{ + int unit = wdunit(dev), part = wdpart(dev), val; + struct disk *du; + + if (unit >= _NWD) /* 31 Jul 92*/ + return(-1); + + du = wddrives[unit]; + if (du == 0 || du->dk_state == 0) + val = wdopen (makewddev(major(dev), unit, WDRAW), FREAD, S_IFBLK, 0); + if (du == 0 || val != 0 || du->dk_flags & DKFL_WRITEPROT) + return (-1); + + return((int)du->dk_dd.d_partitions[part].p_size); +} + +extern char *vmmap; /* poor name! */ + +int +wddump(dev_t dev) /* dump core after a system crash */ +{ + register struct disk *du; /* disk unit to do the IO */ + register struct bt_bad *bt_ptr; + long num; /* number of sectors to write */ + int unit, part, wdc; + long blkoff, blknum, blkcnt; + long cylin, head, sector, stat; + long secpertrk, secpercyl, nblocks, i; + char *addr; + extern int Maxmem; + static wddoingadump = 0 ; + extern caddr_t CADDR1; + + addr = (char *) 0; /* starting address */ + + /* toss any characters present prior to dump */ + while (sgetc(1)) + ; + + /* size of memory to dump */ + num = Maxmem; + unit = wdunit(dev); /* eventually support floppies? */ + part = wdpart(dev); /* file system */ + /* check for acceptable drive number */ + if (unit >= _NWD) return(ENXIO); /* 31 Jul 92*/ + + du = wddrives[unit]; + if (du == 0) return(ENXIO); + /* was it ever initialized ? */ + if (du->dk_state < OPEN) return (ENXIO) ; + if (du->dk_flags & DKFL_WRITEPROT) return(ENXIO); + wdc = du->dk_port; + + /* Convert to disk sectors */ + num = (u_long) num * NBPG / du->dk_dd.d_secsize; + + /* check if controller active */ + /*if (wdtab.b_active) return(EFAULT); */ + if (wddoingadump) return(EFAULT); + + secpertrk = du->dk_dd.d_nsectors; + secpercyl = du->dk_dd.d_secpercyl; + nblocks = du->dk_dd.d_partitions[part].p_size; + blkoff = du->dk_dd.d_partitions[part].p_offset; + +/*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/ + /* check transfer bounds against partition size */ + if ((dumplo < 0) || ((dumplo + num) > nblocks)) + return(EINVAL); + + /*wdtab.b_active = 1; /* mark controller active for if we + panic during the dump */ + wddoingadump = 1 ; i = 100000 ; + while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0)) ; + outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); + outb(wdc+wd_command, WDCC_RESTORE | WD_STEP); + while (inb(wdc+wd_status) & WDCS_BUSY) ; + + /* some compaq controllers require this ... */ + wdsetctlr(dev, du); + + blknum = dumplo + blkoff; + while (num > 0) { +#ifdef notdef + if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER; + if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl) + blkcnt = secpercyl - (blknum % secpercyl); + /* keep transfer within current cylinder */ +#endif + pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE); + + /* compute disk address */ + cylin = blknum / secpercyl; + head = (blknum % secpercyl) / secpertrk; + sector = blknum % secpertrk; + +#ifdef notyet + /* + * See if the current block is in the bad block list. + * (If we have one.) + */ + for (bt_ptr = du->dk_bad.bt_bad; + bt_ptr->bt_cyl != -1; bt_ptr++) { + if (bt_ptr->bt_cyl > cylin) + /* Sorted list, and we passed our cylinder. + quit. */ + break; + if (bt_ptr->bt_cyl == cylin && + bt_ptr->bt_trksec == (head << 8) + sector) { + /* + * Found bad block. Calculate new block addr. + * This starts at the end of the disk (skip the + * last track which is used for the bad block list), + * and works backwards to the front of the disk. + */ + blknum = (du->dk_dd.d_secperunit) + - du->dk_dd.d_nsectors + - (bt_ptr - du->dk_bad.bt_bad) - 1; + cylin = blknum / secpercyl; + head = (blknum % secpercyl) / secpertrk; + sector = blknum % secpertrk; + break; + } + +#endif + sector++; /* origin 1 */ + + /* select drive. */ + outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf)); + while ((inb(wdc+wd_status) & WDCS_READY) == 0) ; + + /* transfer some blocks */ + outb(wdc+wd_sector, sector); + outb(wdc+wd_seccnt,1); + outb(wdc+wd_cyl_lo, cylin); + outb(wdc+wd_cyl_hi, cylin >> 8); +#ifdef notdef + /* lets just talk about this first...*/ + pg ("sdh 0%o sector %d cyl %d addr 0x%x", + inb(wdc+wd_sdh), inb(wdc+wd_sector), + inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ; +#endif + outb(wdc+wd_command, WDCC_WRITE); + + /* Ready to send data? */ + while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ; + if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ; + + outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256); + + if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ; + /* Check data request (should be done). */ + if (inb(wdc+wd_status) & WDCS_DRQ) return(EIO) ; + + /* wait for completion */ + for ( i = WDCTIMEOUT ; inb(wdc+wd_status) & WDCS_BUSY ; i--) { + if (i < 0) return (EIO) ; + } + /* error check the xfer */ + if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ; + + if ((unsigned)addr % (1024*1024) == 0) printf("%d ", num/2048) ; + /* update block count */ + num--; + blknum++ ; + (int) addr += 512; + + /* operator aborting dump? */ + if (sgetc(1)) + return(EINTR); + } + return(0); +} +#endif diff --git a/sys/i386/isa/wdreg.h b/sys/i386/isa/wdreg.h new file mode 100644 index 000000000000..d9389157039b --- /dev/null +++ b/sys/i386/isa/wdreg.h @@ -0,0 +1,143 @@ +/*- + * Copyright (c) 1991 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. + * + * @(#)wdreg.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * Disk Controller register definitions. + */ +#define wd_data 0x0 /* data register (R/W - 16 bits) */ +#define wd_error 0x1 /* error register (R) */ +#define wd_precomp wd_error /* write precompensation (W) */ +#define wd_seccnt 0x2 /* sector count (R/W) */ +#define wd_sector 0x3 /* first sector number (R/W) */ +#define wd_cyl_lo 0x4 /* cylinder address, low byte (R/W) */ +#define wd_cyl_hi 0x5 /* cylinder address, high byte (R/W)*/ +#define wd_sdh 0x6 /* sector size/drive/head (R/W)*/ +#define wd_command 0x7 /* command register (W) */ +#define wd_status wd_command /* immediate status (R) */ + +#define wd_altsts 0x206 /*alternate fixed disk status(via 1015) (R)*/ +#define wd_ctlr 0x206 /*fixed disk controller control(via 1015) (W)*/ +#define WDCTL_4BIT 0x8 /* use four head bits (wd1003) */ +#define WDCTL_RST 0x4 /* reset the controller */ +#define WDCTL_IDS 0x2 /* disable controller interrupts */ +#define wd_digin 0x207 /* disk controller input(via 1015) (R)*/ + +/* + * Status Bits. + */ +#define WDCS_BUSY 0x80 /* Controller busy bit. */ +#define WDCS_READY 0x40 /* Selected drive is ready */ +#define WDCS_WRTFLT 0x20 /* Write fault */ +#define WDCS_SEEKCMPLT 0x10 /* Seek complete */ +#define WDCS_DRQ 0x08 /* Data request bit. */ +#define WDCS_ECCCOR 0x04 /* ECC correction made in data */ +#define WDCS_INDEX 0x02 /* Index pulse from selected drive */ +#define WDCS_ERR 0x01 /* Error detect bit. */ + +#define WDCS_BITS "\020\010busy\006rdy\006wrtflt\005seekdone\004drq\003ecc_cor\002index\001err" + +#define WDERR_BITS "\020\010badblk\007uncorr\006id_crc\005no_id\003abort\002tr000\001no_dam" + +/* + * Commands for Disk Controller. + */ +#define WDCC_RESTORE 0x10 /* disk restore code -- resets cntlr */ + +#define WDCC_READ 0x20 /* disk read code */ +#define WDCC_WRITE 0x30 /* disk write code */ +#define WDCC__LONG 0x02 /* modifier -- access ecc bytes */ +#define WDCC__NORETRY 0x01 /* modifier -- no retrys */ + +#define WDCC_FORMAT 0x50 /* disk format code */ +#define WDCC_DIAGNOSE 0x90 /* controller diagnostic */ +#define WDCC_IDC 0x91 /* initialize drive command */ + +#define WDCC_EXTDCMD 0xE0 /* send extended command */ +#define WDCC_READP 0xEC /* read parameters from controller */ +#define WDCC_CACHEC 0xEF /* cache control */ + +#define WD_STEP 0 /* winchester- default 35us step */ + +#define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */ + + +#ifdef KERNEL +/* + * read parameters command returns this: + */ +struct wdparams { + /* drive info */ + short wdp_config; /* general configuration */ + short wdp_fixedcyl; /* number of non-removable cylinders */ + short wdp_removcyl; /* number of removable cylinders */ + short wdp_heads; /* number of heads */ + short wdp_unfbytespertrk; /* number of unformatted bytes/track */ + short wdp_unfbytes; /* number of unformatted bytes/sector */ + short wdp_sectors; /* number of sectors */ + short wdp_minisg; /* minimum bytes in inter-sector gap*/ + short wdp_minplo; /* minimum bytes in postamble */ + short wdp_vendstat; /* number of words of vendor status */ + /* controller info */ + char wdp_cnsn[20]; /* controller serial number */ + short wdp_cntype; /* controller type */ +#define WDTYPE_SINGLEPORTSECTOR 1 /* single port, single sector buffer */ +#define WDTYPE_DUALPORTMULTI 2 /* dual port, multiple sector buffer */ +#define WDTYPE_DUALPORTMULTICACHE 3 /* above plus track cache */ + short wdp_cnsbsz; /* sector buffer size, in sectors */ + short wdp_necc; /* ecc bytes appended */ + char wdp_rev[8]; /* firmware revision */ + char wdp_model[40]; /* model name */ + short wdp_nsecperint; /* sectors per interrupt */ + short wdp_usedmovsd; /* can use double word read/write? */ +}; + +/* + * wd driver entry points + */ +int wdprobe(struct isa_device *); +int wdattach(struct isa_device *); +int wdstrategy(struct buf *); +void wdintr(struct intrframe); +int wdopen(dev_t, int, int, struct proc *); +int wdclose(dev_t dev, int flags, int fmt); +int wdioctl(dev_t, int, caddr_t, int); +/* int wdformat(struct buf *bp); */ +int wdsize(dev_t); +int wddump(dev_t); + +#endif KERNEL diff --git a/sys/i386/isa/wt.c b/sys/i386/isa/wt.c new file mode 100644 index 000000000000..4376395e1cc0 --- /dev/null +++ b/sys/i386/isa/wt.c @@ -0,0 +1,1162 @@ +/*- + * 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. + * + * @(#)wt.c 7.1 (Berkeley) 5/9/91 + */ + +/* + * + * Copyright (c) 1989 Carnegie-Mellon University. + * All rights reserved. + * + * Authors: Robert Baron + * + * 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 "wt.h" +#if NWT > 0 +/* + * HISTORY + * $Log: wt.c,v $ + * Revision 2.2.1.3 90/01/08 13:29:38 rvb + * Add Intel copyright. + * [90/01/08 rvb] + * + * Revision 2.2.1.2 89/12/21 18:00:09 rvb + * Change WTPRI to make the streamer tape read/write + * interruptible. [lin] + * + * Revision 2.2.1.1 89/11/10 09:49:49 rvb + * ORC likes their streamer port at 0x288. + * [89/11/08 rvb] + * + * Revision 2.2 89/09/25 12:33:02 rvb + * Driver was provided by Intel 9/18/89. + * [89/09/23 rvb] + * + */ + +/* + * + * Copyright 1988, 1989 by Intel Corporation + * + * Support Bell Tech QIC-02 and WANGTEK QIC-36 or QIC-02 + */ + +/*#include <sys/errno.h> +#include <sys/signal.h> +#include <sys/types.h>*/ +#include "sys/param.h" +#include "sys/buf.h" +#include "sys/file.h" +#include "sys/proc.h" +#include "sys/user.h" +#include "i386/isa/wtreg.h" + +#ifdef ORC +unsigned wtport = 0x288; /* base I/O port of controller */ +#else ORC +unsigned wtport = 0x300; /* base I/O port of controller */ +#endif ORC + /* standard = 0x300 */ + /* alternate = 0x338 */ + +unsigned wtchan = 1; /* DMA channel number */ + /* stardard = 1 */ + /* hardware permits 1, 2 or 3. */ + /* (Avoid DMA 2: used by disks) */ + +int first_wtopen_ever = 1; + + +#define ERROR 1 /* return from tape routines */ +#define SUCCESS 0 /* return from tape routines */ + +int wci = 0; +int exflag = 0; +int bytes = 0; + +static unsigned char eqdma = 0x8; +static unsigned char pagereg = 0x83; +static unsigned char dmareg = 2; +static unsigned char dma_write = 0x49; +static unsigned char dma_read = 0x45; +static unsigned char dma_done = 2; +static unsigned char mode = 0; +static unsigned char mbits; /* map bits into each other */ +static long bufptr; +static unsigned numbytes; +/* +_wci dw 0 ; interrupt chain finished normally +_exflag dw 0 ; exception variable +_bytes dw 0 ; current bytes + +eqdma db 8h ; enable dma command: ch1,ch2=8h, ch3=10h +pagereg db 83h ; ch1=83h, ch2=81h, ch3=82h +dmareg db 2 ; ch1=2, ch2=4, ch3=6 +dma_write db 49h ; write dma command: 48h+_wtchan +dma_read db 45h ; read dma command: 44h+_wtchan +dma_done db 2 ; dma done flag: 1<<_wtchan +mode db 0 ; dma operation mode +lbufptr dw 0 ; buffer pointer to data buffers, low word +hbufptr dw 0 ; buffer pointer to data buffers, high word +numbytes dw 0 ; number of bytes to read or write (new) +*/ + +#define PAGESIZ 4096 +#define HZ 60 + +/* tape controller ports */ +#define STATPORT wtport +#define CTLPORT STATPORT +#define CMDPORT (wtport+1) +#define DATAPORT CMDPORT + +/* defines for reading out status from wangtek tape controller */ +#define READY 0x01 /* ready bit define */ +#define EXCEP 0x02 /* exception bit define */ +#define STAT (READY|EXCEP) +#define RESETMASK 0x7 +#define RESETVAL (RESETMASK & ~EXCEP) + +/* tape controller control bits (CTLPORT) */ +#define ONLINE 0x01 +#define RESET 0x02 +#define REQUEST 0x04 /* request command */ +#define CMDOFF 0xC0 + +/* QIC-02 commands (CMDPORT) */ +#define RDDATA 0x80 /* read data */ +#define READFM 0xA0 /* read file mark */ +#define WRTDATA 0x40 /* write data */ +#define WRITEFM 0x60 /* write file mark */ +#define RDSTAT 0xC0 /* read status command */ +#define REWIND 0x21 /* rewind command (position+bot) */ + +/* 8237 DMA controller regs */ +#define STATUSREG 0x8 +#define MASKREG 0xA +#define MODEREG 0xB +#define CLEARFF 0xC + +/* streamer tape block size */ +#define BLKSIZE 512 + +/* Tape characteristics */ +#define NBPS 512 /* 512-byte blocks */ +#define ERROR 1 /* return from tape routines */ +#define SUCCESS 0 /* return from tape routines */ + +/* Minor devs */ +#define TP_REWCLOSE(d) ((minor(d)&04) == 0) /* Rewind tape on close if read/write */ +#define TP_DENS(dev) ((minor(dev) >> 3) & 03) /* set density */ +#define TPHOG(d) 0 /* use Hogproc during tape I/O */ + +/* defines for wtflags */ +#define TPINUSE 0x0001 /* tape is already open */ +#define TPREAD 0x0002 /* tape is only open for reading */ +#define TPWRITE 0x0004 /* tape is only open for writing */ +#define TPSTART 0x0008 /* tape must be rewound and reset */ +#define TPDEAD 0x0010 /* tape drive does not work or driver error */ +#define TPSESS 0x0020 /* no more reads or writes allowed in session */ + /* for example, when tape has to be changed */ +#define TPSTOP 0x0040 /* Stop command outstanding */ +#define TPREW 0x0080 /* Rewind command outstanding, see wtdsl2() */ +#define TPVOL 0x0100 /* Read file mark, or hit end of tape */ +#define TPWO 0x0200 /* write command outstanding */ +#define TPRO 0x0400 /* read command outstanding */ +#define TPWANY 0x0800 /* write command requested */ +#define TPRANY 0x1000 /* read command requested */ +#define TPWP 0x2000 /* write protect error seen */ + +unsigned int wtflags = TPSTART; /* state of tape drive */ + +struct buf rwtbuf; /* header for raw i/o */ +struct proc *myproc; /* process which opened tape driver */ + +char wtimeron; /* wtimer() active flag */ +char wtio; /* dma (i/o) active flag */ +char isrlock; /* isr() flag */ + +struct proc * Hogproc; /* no Hogproc on Microport */ +#define ftoseg(x) ((unsigned) (x >> 16)) + +struct wtstatus { + ushort wt_err; /* code for error encountered */ + ushort wt_ercnt; /* number of error blocks */ + ushort wt_urcnt; /* number of underruns */ +} wterror; + +/* defines for wtstatus.wt_err */ +#define TP_POR 0x100 /* Power on/reset occurred */ +#define TP_RES1 0x200 /* Reserved for end of media */ +#define TP_RES2 0x400 /* Reserved for bus parity */ +#define TP_BOM 0x800 /* Beginning of media */ +#define TP_MBD 0x1000 /* Marginal block detected */ +#define TP_NDT 0x2000 /* No data detected */ +#define TP_ILL 0x4000 /* Illegal command */ +#define TP_ST1 0x8000 /* Status byte 1 bits */ +#define TP_FIL 0x01 /* File mark detected */ +#define TP_BNL 0x02 /* Bad block not located */ +#define TP_UDA 0x04 /* Unrecoverable data error */ +#define TP_EOM 0x08 /* End of media */ +#define TP_WRP 0x10 /* Write protected cartridge */ +#define TP_USL 0x20 /* Unselected drive */ +#define TP_CNI 0x40 /* Cartridge not in place */ +#define TP_ST0 0x80 /* Status byte 0 bits */ + +/* Grounds for reporting I/O error to user */ +#define TP_ERR0 (TP_BNL|TP_UDA|TP_WRP|TP_CNI|TP_FIL|TP_EOM|TP_USL) +#define TP_ERR1 (TP_MBD|TP_NDT|TP_ILL) +/* TP_ILL should never happen! */ +/* +#define TP_ERR0 0x7f +#define TP_ERR1 0x7700 +*/ + +/* defines for reading out status from wangtek tape controller */ +#define READY 0x01 /* ready bit define */ +#define EXCEP 0x02 /* exception bit define */ + +/* sleep priority */ +#define WTPRI (PZERO+10) + +char pagebuf[NBPS]; /* buffer of size NBPS */ +unsigned long pageaddr; /* physical addr of pagebuf */ + /* pageaddr is used with DMA controller */ +time_t Hogtime; /* lbolt when Hog timer started */ +extern time_t lbolt; + +#define debug printf + +/* + * Strategy routine. + * + * Arguments: + * Pointer to buffer structure + * Function: + * Start transfer. + * + * It would be nice to have this multiple-threaded. + * There is a version of dump from Berkeley that works with multiple processes + * trading off with disk & tape I/O. + */ + +int +wtstrategy(bp) +register struct buf *bp; +{ + unsigned ucnt1, ucnt2, finished; + unsigned long adr1, adr2; + int bad; + + adr1 = kvtop(bp->b_un.b_addr); +#ifdef DEBUG + debug("bpaddr %x\n", adr1); +#endif + ucnt1 = bp->b_bcount % NBPG; + ucnt2 = 0; + adr2 = 0; +#ifdef DEBUG + debug("WTstart: adr1 %lx cnt %x\n", adr1, ucnt1); +#endif + /* 64K boundary? (XXX) */ + if (ftoseg(adr1) != ftoseg(adr1 + (unsigned) ucnt1 - 1)) + { + adr2 = (adr1 & 0xffff0000L) + 0x10000L; + ucnt2 = (adr1 + ucnt1) - adr2; + ucnt1 -= ucnt2; + } + /* page boundary? */ + if (trunc_page(adr1) != trunc_page(adr1 + (unsigned) ucnt1 - 1)) + { unsigned u; + u = NBPG - ((unsigned)bp->b_un.b_addr & (NBPG-1)); + adr2 = kvtop(bp->b_un.b_addr + u); + ucnt2 = ucnt1 - u; + ucnt1 = u; + } + /* at file marks and end of tape, we just return '0 bytes available' */ + if (wtflags & TPVOL) { + bp->b_resid = bp->b_bcount; + goto xit; + } + if ((Hogproc == (struct proc *) 0) && TPHOG(bp->b_dev)) + { +#ifdef DEBUG + printf("setting Hogproc\n"); +#endif + Hogtime = 0; + Hogproc = myproc; + } + if (bp->b_flags & B_READ) { + bad = 0; + + /* For now, we assume that all data will be copied out */ + /* If read command outstanding, just skip down */ + if (!(wtflags & TPRO)) { + if (ERROR == wtsense(TP_WRP)) /* clear status */ + goto errxit; +#ifdef DEBUG + debug("WTread: Start read\n"); +#endif + if (!(wtflags & TPREAD) || (wtflags & TPWANY) || + (rstart() == ERROR)) { +#ifdef DEBUG + debug("Tpstart: read init error\n"); /* */ +#endif + goto errxit; + } + wtflags |= TPRO|TPRANY; + } + + finished = 0; + /* Take a deep breath */ + if (ucnt1) { + if ((rtape(adr1, ucnt1) == ERROR) && + (wtsense(TP_WRP) == ERROR)) + goto endio; + /* wait for it */ + bad = pollrdy(); + finished = bytes; + if (bad) + goto endio; + } + /* if a second I/O region, start it */ + if (ucnt2) { + if ((rtape(adr2, ucnt2) == ERROR) && + (wtsense(TP_WRP) == ERROR)) + ucnt2 = 0; /* don't poll for me */ + } + + /* if second i/o pending wait for it */ + if (ucnt2) { + pollrdy(); + /* whether pollrdy is ok or not */ + finished += bytes; + } + } else { + if (wtflags & TPWP) /* write protected */ + goto errxit; + + /* If write command outstanding, just skip down */ + if (!(wtflags & TPWO)) { + if (ERROR == wtsense(0)) /* clear status */ + { +#ifdef DEBUG + debug("TPstart: sense 0\n"); +#endif + goto errxit; + } + if (!(wtflags & TPWRITE) || (wtflags & TPRANY) || + (wstart() == ERROR)) { +#ifdef DEBUG + debug("Tpstart: write init error\n"); /* */ +#endif + wtsense(0); + +errxit: bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + goto xit; + } + wtflags |= TPWO|TPWANY; + } + + /* and hold your nose */ + if (ucnt1 && ((wtape(adr1, ucnt1) == ERROR) + && (wtsense(0) == ERROR))) + finished = bytes; + + else if (ucnt2 && + (((ucnt1 && pollrdy()) || + (wtape(adr2, ucnt2) == ERROR)) && + (wtsense(0) == ERROR))) + finished = ucnt1 + NBPS + bytes; + /* All writes and/or copyins were fine! */ + else + finished = bp->b_bcount; + bad = pollrdy(); + } + + endio: + if(bad == EIO) bad = 0; + wterror.wt_err = 0; + if (exflag && wtsense((bp->b_flags & B_READ) ? TP_WRP : 0)) { + if ((wterror.wt_err & TP_ST0) + && (wterror.wt_err & (TP_FIL|TP_EOM))) { +#ifdef DEBUG + debug("WTsta: Hit end of tape\n"); /* */ +#endif + wtflags |= TPVOL; + if (wterror.wt_err & TP_FIL) { + if (wtflags & TPRO) + /* interrupter is bogus */ + rstart(); /* restart read command */ + else + wtflags &= ~TPWO; + finished += NBPS; + } + /* Reading file marks or writing end of tape return 0 bytes */ + } else { + bp->b_flags |= B_ERROR; + wtflags &= ~(TPWO|TPRO); + } + } + + if(bad) { + bp->b_flags |= B_ERROR; + bp->b_error = bad; + } + bp->b_resid = bp->b_bcount - finished; +xit: + biodone(bp); + if (wtimeron) + Hogtime = lbolt; + else if (Hogproc == myproc) + Hogproc = (struct proc *) 0; +} + +/* + * simulate an interrupt periodically while I/O is going + * this is necessary in case interrupts get eaten due to + * multiple devices on a single IRQ line + */ +wtimer() +{ + /* If I/O going and not in isr(), simulate interrupt + * If no I/O for at least 1 second, stop being a Hog + * If I/O done and not a Hog, turn off wtimer() + */ + if (wtio && !isrlock) + isr(); + + if ((Hogproc == myproc) && Hogtime && (lbolt-Hogtime > HZ)) + Hogproc = (struct proc *) 0; + + if (wtio || (Hogproc == myproc)) + timeout(wtimer, (caddr_t) 0, HZ); + else + wtimeron = 0; +} + + +wtrawio(bp) +struct buf *bp; +{ + wtstrategy(bp); + biowait(bp); + return(0); +} + +/* + * ioctl routine + * for user level QIC commands only + */ +wtioctl(dev, cmd, arg, mode) +int dev, cmd; +unsigned long arg; +int mode; +{ + if (cmd == WTQICMD) + { + if ((qicmd((int)arg) == ERROR) || (rdyexc(HZ) == ERROR)) + { + wtsense(0); + return(EIO); + } + return(0); + } + return(EINVAL); +} + +/* + * open routine + * called on every device open + */ +wtopen(dev, flag) +int dev, flag; +{ + if (first_wtopen_ever) { + wtinit(); + first_wtopen_ever = 0; + } +#ifdef DEBUG + printf("wtopen ...\n"); +#endif + if (!pageaddr) { + return(ENXIO); + } + if (wtflags & (TPINUSE)) { + return(ENXIO); + } + if (wtflags & (TPDEAD)) { + return(EIO); + } + /* If a rewind from the last session is going on, wait */ + while(wtflags & TPREW) { +#ifdef DEBUG + debug("Waiting for rew to finish\n"); +#endif + DELAY(1000000); /* delay one second */ + } + /* Only do reset and select when tape light is off, and tape is rewound. + * This allows multiple volumes. */ + if (wtflags & TPSTART) { + if (t_reset() != SUCCESS) { + return(ENXIO); + } +#ifdef DEBUG + debug("reset done. calling wtsense\n"); +#endif + if (wtsense(TP_WRP) == ERROR) { + return (EIO); + } +#ifdef DEBUG + debug("wtsense done\n"); +#endif + wtflags &= ~TPSTART; + } + + wtflags = TPINUSE; + if (flag & FREAD) + wtflags |= TPREAD; + if (flag & FWRITE) + wtflags |= TPWRITE; + rwtbuf.b_flags = 0; + myproc = curproc; /* for comparison */ +#ifdef not + switch(TP_DENS(dev)) { +case 0: +cmds(0x28); +break; +case 1: +cmds(0x29); +break; +case 2: +cmds(0x27); +break; +case 3: +cmds(0x24); + } +#endif + return(0); +} + +/* + * close routine + * called on last device close + * If not rewind-on-close, leave read or write command intact. + */ +wtclose(dev) +{ + int wtdsl2(); + +#ifdef DEBUG + debug("WTclose:\n"); +#endif + if (Hogproc == myproc) + Hogproc = (struct proc *) 0; + if (!exflag && (wtflags & TPWANY) && !(wtflags & (TPSESS|TPDEAD))) { + if (!(wtflags & TPWO)) + wstart(); +#ifdef DEBUG + debug("WT: Writing file mark\n"); +#endif + wmark(); /* write file mark */ +#ifdef DEBUG + debug("WT: Wrote file mark, going to wait\n"); +#endif + if (rdyexc(HZ/10) == ERROR) { + wtsense(0); + } + } + if (TP_REWCLOSE(dev) || (wtflags & (TPSESS|TPDEAD))) { + /* rewind tape to beginning of tape, deselect tape, and make a note */ + /* don't wait until rewind, though */ + /* Ending read or write causes rewind to happen, if no error, + * and READY and EXCEPTION stay up until it finishes */ + if (wtflags & (TPRO|TPWO)) + { +#ifdef DEBUG + debug("End read or write\n"); +#endif + rdyexc(HZ/10); + ioend(); + wtflags &= ~(TPRO|TPWO); + } + else wtwind(); + wtflags |= TPSTART | TPREW; + timeout(wtdsl2, 0, HZ); + } + else if (!(wtflags & (TPVOL|TPWANY))) + { + /* space forward to after next file mark no writing done */ + /* This allows skipping data without reading it.*/ +#ifdef DEBUG + debug("Reading past file mark\n"); +#endif + if (!(wtflags & TPRO)) + rstart(); + rmark(); + if (rdyexc(HZ/10)) + { + wtsense(TP_WRP); + } + } + wtflags &= TPREW|TPDEAD|TPSTART|TPRO|TPWO; + return(0); +} + +/* return ERROR if user I/O request should receive an I/O error code */ + +wtsense(ignor) +{ + wtflags &= ~(TPRO|TPWO); +#ifdef DEBUGx + debug("WTsense: start "); +#endif + if (rdstatus(&wterror) == ERROR) + { +#ifdef DEBUG + debug("WTsense: Can't read status\n"); +#endif + return(ERROR); + } +#ifdef DEBUG + if (wterror.wt_err & (TP_ST0|TP_ST1)) + { + debug("Tperror: status %x error %d underruns %d\n", + wterror.wt_err, wterror.wt_ercnt, wterror.wt_urcnt); + } + else + debug("done. no error\n"); +#endif + wterror.wt_err &= ~ignor; /* ignore certain errors */ + reperr(wterror.wt_err); + if (((wterror.wt_err & TP_ST0) && (wterror.wt_err & TP_ERR0)) || + ((wterror.wt_err & TP_ST1) && (wterror.wt_err & TP_ERR1))) + return ERROR; + + return SUCCESS; +} + +/* lifted from tdriver.c from Wangtek */ +reperr(srb0) +int srb0; +{ + int s0 = srb0 & (TP_ERR0|TP_ERR1); /* find out which exception to report */ + + if (s0) { + if (s0 & TP_USL) + sterr("Drive not online"); + else if (s0 & TP_CNI) + sterr("No cartridge"); + else if ((s0 & TP_WRP) && !(wtflags & TPWP)) + { + sterr("Tape is write protected"); + wtflags |= TPWP; + } + /* + if (s0 & TP_FIL) + sterr("Filemark detected"); + */ + else if (s0 & TP_BNL) + sterr("Block in error not located"); + else if (s0 & TP_UDA) + sterr("Unrecoverable data error"); + /* + else if (s0 & TP_EOM) + sterr("End of tape"); + */ + else if (s0 & TP_NDT) + sterr("No data detected"); + /* + if (s0 & TP_POR) + sterr("Reset occured"); + */ + else if (s0 & TP_BOM) + sterr("Beginning of tape"); + else if (s0 & TP_ILL) + sterr("Illegal command"); + } +} + +sterr(errstr) +char *errstr; +{ + printf("Streamer: %s\n", errstr); +} + +/* Wait until rewind finishes, and deselect drive */ +wtdsl2() { + int stat; + + stat = inb(wtport) & (READY|EXCEP); +#ifdef DEBUG + debug("Timeout: Waiting for rewind to finish: stat %x\n", stat); +#endif + switch (stat) { + /* They're active low, ya'know */ + case READY|EXCEP: + timeout(wtdsl2, (caddr_t) 0, HZ); + return; + case EXCEP: + wtflags &= ~TPREW; + return; + case READY: + case 0: + wtflags &= ~TPREW; + sterr("Rewind failed"); + wtsense(TP_WRP); + return; + } + } + +wtwind() { +#ifdef DEBUG + debug("WT: About to rewind\n"); +#endif + rwind(); /* actually start rewind */ +} + +wtintr(unit) { + if (wtflags & (TPWO|TPRO)) + { + isrlock = 1; + if (wtio) isr(); + isrlock = 0; + } +} + +wtinit() { + if (wtchan < 1 || wtchan > 3) + { + sterr("Bad DMA channel, cannot init driver"); + return; + } + wtlinit(); /* init assembly language variables */ + pageset(); +} + +rdyexc(ticks) +{ + int s; +#ifdef DEBUG + int os = 0xffff; /* force printout first time */ +#endif + for (;;) { /* loop until ready or exception */ + s=(inb(wtport) & 0xff); /* read the status register */ +#ifdef DEBUG + if (os != s) { + debug("Status reg = %x\n", s); /* */ + os = s; + } +#endif + if (!(s & EXCEP)) /* check if exception have occured */ + break; + if (!(s & READY)) /* check if controller is ready */ + break; + s = splbio(); + DELAY((ticks/HZ)*1000000); /* */ + splx(s); + } +#ifdef DEBUG + debug("Status reg = %x on return\n", s); /* */ +#endif + return((s & EXCEP)?SUCCESS:ERROR); /* return exception if it occured */ +} + +pollrdy() +{ + int sps; +#ifdef DEBUG + debug("Pollrdy\n"); +#endif + sps = splbio(); + while (wtio) { + int error; + + if (error = tsleep((caddr_t)&wci, WTPRI | PCATCH, + "wtpoll", 0)) { + splx(sps); + return(error); + } + } + splx(sps); +#ifdef DEBUG + debug("Finish poll, wci %d exflag %d\n", wci, exflag); +#endif + return (EIO); +} + +wtdma() /* start up i/o operation, called from dma() in wtlib1.s */ +{ + wtio = 1; + if (!wtimeron) + { + wtimeron = 1; + timeout(wtimer, (caddr_t) 0, HZ/2); + } +} + +wtwake() /* end i/o operation, called from isr() in wtlib1.s */ +{ + wtio = 0; + wakeup(&wci); +} + +pageset() +{ + unsigned long pp; + + pp = (unsigned long) pagebuf; + pageaddr = kvtop(pp); +#ifdef DEBUG + debug("pageset: addr %lx\n", pageaddr); +#endif +} + + + +#define near + +static near +sendcmd() +{ + /* desired command in global mbits */ + + outb(CTLPORT, mbits | REQUEST); /* set request */ + while (inb(STATPORT) & READY); /* wait for ready */ + outb(CTLPORT, mbits & ~REQUEST); /* reset request */ + while ((inb(STATPORT) & READY) == 0); /* wait for not ready */ +} + +static near /* execute command */ +cmds(cmd) +{ + register s; + + do s = inb(STATPORT); + while ((s & STAT) == STAT); /* wait for ready */ + + if ((s & EXCEP) == 0) /* if exception */ + return ERROR; /* error */ + + outb(CMDPORT, cmd); /* output the command */ + + outb(CTLPORT, mbits=ONLINE); /* set & send ONLINE */ + sendcmd(); + + return SUCCESS; +} + +qicmd(cmd) +{ + return cmds(cmd); +} + +rstart() +{ + return cmds(RDDATA); +} + +rmark() +{ + return cmds(READFM); +} + +wstart() +{ + return cmds(WRTDATA); +} + +ioend() +{ + register s; + register rval = SUCCESS; + + do s = inb(STATPORT); + while ((s & STAT) == STAT); /* wait for ready */ + + if ((s & EXCEP) == 0) /* if exception */ + rval = ERROR; /* error */ + + mbits &= ~ONLINE; + outb(CTLPORT, mbits); /* reset ONLINE */ + outb(MASKREG, wtchan+4); /* turn off dma */ + outb(CLEARFF, 0); /* reset direction flag */ + + return rval; +} + +wmark() +{ + register s; + + if (cmds(WRITEFM) == ERROR) + return ERROR; + + do s = inb(STATPORT); + while ((s & STAT) == STAT); /* wait for ready */ + + if ((s & EXCEP) == 0) /* if exception */ + return ERROR; /* error */ + + return SUCCESS; +} + +rwind() +{ + register s; + + mbits = CMDOFF; + + do s = inb(STATPORT); + while ((s & STAT) == STAT); /* wait for ready */ + + outb(CMDPORT, REWIND); + sendcmd(); + + return SUCCESS; +} + +rdstatus(stp) +char *stp; /* pointer to 6 byte buffer */ +{ + register s; + int n; + + do s = inb(STATPORT); + while ((s & STAT) == STAT); /* wait for ready or exception */ + + outb(CMDPORT, RDSTAT); + sendcmd(); /* send read status command */ + + for (n=0; n<6; n++) + { +#ifdef DEBUGx + debug("rdstatus: waiting, byte %d\n", n); +#endif + do s = inb(STATPORT); + while ((s & STAT) == STAT); /* wait for ready */ +#ifdef DEBUGx + debug("rdstatus: done\n"); +#endif + if ((s & EXCEP) == 0) /* if exception */ + return ERROR; /* error */ + + *stp++ = inb(DATAPORT); /* read status byte */ + + outb(CTLPORT, mbits | REQUEST); /* set request */ +#ifdef DEBUGx + debug("rdstatus: waiting after request, byte %d\n", n); +#endif + while ((inb(STATPORT)&READY) == 0); /* wait for not ready */ + for (s=100; s>0; s--); /* wait an additional time */ + + outb(CTLPORT, mbits & ~REQUEST);/* unset request */ +#ifdef DEBUGx + debug("rdstatus: done\n"); +#endif + } + return SUCCESS; +} + +t_reset() +{ + register i; + mbits |= RESET; + outb(CTLPORT, mbits); /* send reset */ + DELAY(20); + mbits &= ~RESET; + outb(CTLPORT, mbits); /* turn off reset */ + if ((inb(STATPORT) & RESETMASK) == RESETVAL) + return SUCCESS; + return ERROR; +} + +static +dma() +{ + int x=splbio(); + wtdma(); + outb(CLEARFF, 0); + outb(MODEREG, mode); /* set dma mode */ + outb(dmareg, bufptr & 0xFF); + outb(dmareg, (bufptr>>8) & 0xFF); + outb(pagereg, (bufptr>>16) & 0xFF); + outb(dmareg+1, (BLKSIZE-1) & 0xFF); + outb(dmareg+1, (BLKSIZE-1) >> 8); + outb(wtport, eqdma+ONLINE); + outb(MASKREG, wtchan); /* enable command to 8237, start dma */ + splx(x); +} + +static near +wtstart(buf, cnt) +long buf; +int cnt; +{ + register s; + + bufptr = buf; /* init statics */ + numbytes = cnt; + wci = 0; /* init flags */ + exflag = 0; + bytes = 0; /* init counter */ + + do s = inb(STATPORT) & STAT; + while (s == STAT); /* wait for ready or error */ + + if (s & EXCEP) /* no error */ + { + dma(); + return SUCCESS; + } + return ERROR; /* error */ +} + +rtape(buf, cnt) +long buf; /* physical address */ +int cnt; /* number of bytes */ +{ + mode = dma_read; + return wtstart(buf,cnt); +} + +wtape(buf, cnt) +long buf; /* physical address */ +int cnt; /* number of bytes */ +{ + mode = dma_write; + return wtstart(buf,cnt); +} + +isr() +{ + int stat = inb(wtport); + if (!(stat & EXCEP)) /* exception during I/O */ + { + if (bytes + BLKSIZE >= numbytes) wci = 1; + exflag = 1; + goto isrwake; + } + if ((stat & READY) || !(inb(STATUSREG) & dma_done)) + return; + exflag = 0; + outb(wtport, ONLINE); + bytes += BLKSIZE; + if (bytes >= numbytes) /* normal completion of I/O */ + { + wci = 1; +isrwake: + outb(MASKREG, 4+wtchan); /* turn off dma */ + wtwake(); /* wake up user level */ + } + else + { /* continue I/O */ + bufptr += BLKSIZE; + dma(); + } +} + +wtlinit() +{ + switch (wtchan) { + case 1: + return; + case 2: + pagereg = 0x81; + dma_done = 4; + break; + case 3: + eqdma = 0x10; + pagereg = 0x82; + dma_done = 8; + break; + } + dma_write = wtchan+0x48; + dma_read = wtchan+0x44; + dmareg = wtchan+wtchan; +} + +wtsize() +{ +} + +wtdump() +{ +} + +#include "i386/isa/isa_device.h" +#include "i386/isa/icu.h" + +int wtprobe(), wtattach(); +struct isa_driver wtdriver = { + wtprobe, wtattach, "wt", +}; + +wtprobe(dvp) + struct isa_device *dvp; +{ + int val,i,s; + +#ifdef lint + wtintr(0); +#endif + + wtport = dvp->id_iobase; + if(t_reset() != SUCCESS) return(0); + return(1); +} + +wtattach() { } + +#endif NWT diff --git a/sys/i386/isa/wtreg.h b/sys/i386/isa/wtreg.h new file mode 100644 index 000000000000..8f79ca1dce87 --- /dev/null +++ b/sys/i386/isa/wtreg.h @@ -0,0 +1,95 @@ +/*- + * 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. + * + * @(#)wtreg.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * + * Copyright (c) 1989 Carnegie-Mellon University. + * All rights reserved. + * + * Authors: Robert Baron + * + * 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. + */ + +/* + * HISTORY + * $Log: wtreg.h,v $ + * Revision 2.2.1.1 90/01/08 13:29:25 rvb + * Add Intel copyright. + * [90/01/08 rvb] + * + * Revision 2.2 89/09/25 12:33:09 rvb + * Driver was provided by Intel 9/18/89. + * [89/09/23 rvb] + * + */ + +/* + * + * Copyright 1988, 1989 by Intel Corporation + * + */ + +/* + * wtioctl.h + * defines ioctl parameters for direct QIC commands + */ + +#define WTIOC ('W'<<8) +#define WTQICMD (WTIOC|0) + +/* QIC commands allowed */ +#define SELECT 0x01 +#define REWIND 0x21 +#define ERASE 0x22 +#define RETENS 0x24 diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c new file mode 100644 index 000000000000..0fb77012d090 --- /dev/null +++ b/sys/isa/atrtc.c @@ -0,0 +1,271 @@ +/*- + * 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. + * + * @(#)clock.c 7.2 (Berkeley) 5/12/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 5 00158 + * -------------------- ----- ---------------------- + * + * 14 Aug 92 Arne Henrik Juul Added code in the kernel to + * allow for DST in the BIOS. + * 17 Jan 93 Bruce Evans Fixed leap year and second + * calculations + * 01 Feb 93 Julian Elischer Added code to for the cpu + * speed independent spinwait() + * function, (used by scsi and others) + * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1 + * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock + * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait + * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I + * still kept the other fixes... Had to + * add back in findcpuspeed that Bruce + * had removed. + */ + +/* + * Primitive clock interrupt routines. + */ +#include "param.h" +#include "systm.h" +#include "time.h" +#include "kernel.h" +#include "machine/segments.h" +#include "i386/isa/icu.h" +#include "i386/isa/isa.h" +#include "i386/isa/rtc.h" +#include "i386/isa/timerreg.h" + +#define DAYST 119 +#define DAYEN 303 + +/* X-tals being what they are, it's nice to be able to fudge this one... */ +/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */ +#ifndef TIMER_FREQ +#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */ +#endif + +startrtclock() { + int s; + + findcpuspeed(); /* use the clock (while it's free) + to find the cpu speed */ + /* initialize 8253 clock */ + outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); + + /* Correct rounding will buy us a better precision in timekeeping */ + outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz); + outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256); + + /* initialize brain-dead battery powered clock */ + outb (IO_RTC, RTC_STATUSA); + outb (IO_RTC+1, 0x26); + outb (IO_RTC, RTC_STATUSB); + outb (IO_RTC+1, 2); + + outb (IO_RTC, RTC_DIAG); + if (s = inb (IO_RTC+1)) + printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); + outb (IO_RTC, RTC_DIAG); + outb (IO_RTC+1, 0); +} + +unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ + +#define FIRST_GUESS 0x2000 +findcpuspeed() +{ + unsigned char low; + unsigned int remainder; + + /* Put counter in count down mode */ + outb(IO_TIMER1+3, 0x34); + outb(IO_TIMER1, 0xff); + outb(IO_TIMER1, 0xff); + delaycount = FIRST_GUESS; + spinwait(1); + /* Read the value left in the counter */ + low = inb(IO_TIMER1); /* least siginifcant */ + remainder = inb(IO_TIMER1); /* most significant */ + remainder = (remainder<<8) + low ; + /* Formula for delaycount is : + * (loopcount * timer clock speed)/ (counter ticks * 1000) + */ + delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder); +} + + +/* convert 2 digit BCD number */ +bcd(i) +int i; +{ + return ((i/16)*10 + (i%16)); +} + +/* convert years to seconds (from 1970) */ +unsigned long +ytos(y) +int y; +{ + int i; + unsigned long ret; + + ret = 0; + for(i = 1970; i < y; i++) { + if (i % 4) ret += 365*24*60*60; + else ret += 366*24*60*60; + } + return ret; +} + +/* convert months to seconds */ +unsigned long +mtos(m,leap) +int m,leap; +{ + int i; + unsigned long ret; + + ret = 0; + for(i=1;i<m;i++) { + switch(i){ + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + ret += 31*24*60*60; break; + case 4: case 6: case 9: case 11: + ret += 30*24*60*60; break; + case 2: + if (leap) ret += 29*24*60*60; + else ret += 28*24*60*60; + } + } + return ret; +} + + +/* + * Initialize the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +inittodr(base) + time_t base; +{ + unsigned long sec; + int leap,day_week,t,yd; + int sa,s; + + /* do we have a realtime clock present? (otherwise we loop below) */ + sa = rtcin(RTC_STATUSA); + if (sa == 0xff || sa == 0) return; + + /* ready for a read? */ + while ((sa&RTCSA_TUP) == RTCSA_TUP) + sa = rtcin(RTC_STATUSA); + + sec = bcd(rtcin(RTC_YEAR)) + 1900; + if (sec < 1970) + sec += 100; + leap = !(sec % 4); sec = ytos(sec); /* year */ + yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */ + t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */ + day_week = rtcin(RTC_WDAY); /* day */ + sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */ + sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */ + sec += bcd(rtcin(RTC_SEC)); /* seconds */ + + /* XXX off by one? Need to calculate DST on SUNDAY */ + /* Perhaps we should have the RTC hold GMT time to save */ + /* us the bother of converting. */ + yd = yd / (24*60*60); + if ((yd >= DAYST) && ( yd <= DAYEN)) { + sec -= 60*60; + } + sec += tz.tz_minuteswest * 60; + + time.tv_sec = sec; +} + +#ifdef garbage +/* + * Initialze the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +test_inittodr(base) + time_t base; +{ + + outb(IO_RTC,9); /* year */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,8); /* month */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,7); /* day */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,4); /* hour */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,2); /* minutes */ + printf("%d ",bcd(inb(IO_RTC+1))); + outb(IO_RTC,0); /* seconds */ + printf("%d\n",bcd(inb(IO_RTC+1))); + + time.tv_sec = base; +} +#endif + +/* + * Restart the clock. + */ +resettodr() +{ +} + +/* + * Wire clock interrupt in. + */ +#define V(s) __CONCAT(V, s) +extern V(clk)(); +enablertclock() { + setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); + INTREN(IRQ0); +} + +/* + * Delay for some number of milliseconds. + */ +void +spinwait(millisecs) + int millisecs; +{ + DELAY(1000 * millisecs); +} diff --git a/sys/isa/fd.c b/sys/isa/fd.c new file mode 100644 index 000000000000..a461e8153dff --- /dev/null +++ b/sys/isa/fd.c @@ -0,0 +1,903 @@ +/*#define DEBUG 1*/ +/*- + * 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 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00153 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Julian Elischer Heavily re worked, see notes below + * + * Largely rewritten to handle multiple controllers and drives + * By Julian Elischer, Sun Apr 4 16:34:33 WST 1993 + */ +char rev[] = "$Revision: 1.10 $"; +/* + * $Header: /usr/src/sys.386bsd/i386/isa/RCS/fd.c,v 1.10 93/04/13 16:53:29 root Exp $ + */ +/* + * $Log: fd.c,v $ + * Revision 1.10 93/04/13 16:53:29 root + * make sure turning off a drive motor doesn't deselect another + * drive active at the time. + * Also added a pointer from the fd_data to it's fd_type. + * + * Revision 1.9 93/04/13 15:31:02 root + * make all seeks go through DOSEEK state so are sure of being done right. + * + * Revision 1.8 93/04/12 21:20:13 root + * only check if old fd is the one we are working on if there IS + * an old fd pointer. (in fdstate()) + * + * Revision 1.7 93/04/11 17:05:35 root + * cleanup timeouts etc. + * also fix bug to select teh correct drive when running > 1 drive + * at a time. + * + * Revision 1.6 93/04/05 00:48:45 root + * change a timeout and add version to banner message + * + * Revision 1.5 93/04/04 16:39:08 root + * first working version.. some floppy controllers don't seem to + * like 2 int. status inquiries in a row. + * + */ + +#include "fd.h" +#if NFD > 0 + +#include "param.h" +#include "dkbad.h" +#include "systm.h" +#include "conf.h" +#include "file.h" +#include "ioctl.h" +#include "buf.h" +#include "uio.h" +#include "i386/isa/isa.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/fdreg.h" +#include "i386/isa/icu.h" +#include "i386/isa/rtc.h" +#undef NFD +#define NFD 2 + +#define FDUNIT(s) ((s>>3)&1) +#define FDTYPE(s) ((s)&7) + +#define b_cylin b_resid +#define FDBLK 512 +#define NUMTYPES 4 + +struct fd_type { + int sectrac; /* sectors per track */ + int secsize; /* size code for sectors */ + int datalen; /* data len when secsize = 0 */ + int gap; /* gap len between sectors */ + int tracks; /* total num of tracks */ + int size; /* size of disk in sectors */ + int steptrac; /* steps per cylinder */ + int trans; /* transfer speed code */ + int heads; /* number of heads */ +}; + +struct fd_type fd_types[NUMTYPES] = +{ + { 18,2,0xFF,0x1B,80,2880,1,0,2 }, /* 1.44 meg HD 3.5in floppy */ + { 15,2,0xFF,0x1B,80,2400,1,0,2 }, /* 1.2 meg HD floppy */ + { 9,2,0xFF,0x23,40,720,2,1,2 }, /* 360k floppy in 1.2meg drive */ + { 9,2,0xFF,0x2A,40,720,1,1,2 }, /* 360k floppy in DD drive */ +}; + +#define DRVS_PER_CTLR 2 +/***********************************************************************\ +* Per controller structure. * +\***********************************************************************/ +struct fdc_data +{ + int fdcu; /* our unit number */ + int baseport; + int dmachan; + int flags; +#define FDC_ATTACHED 0x01 + struct fd_data *fd; + int fdu; /* the active drive */ + struct buf head; /* Head of buf chain */ + struct buf rhead; /* Raw head of buf chain */ + int state; + int retry; + int status[7]; /* copy of the registers */ +}fdc_data[(NFD+1)/DRVS_PER_CTLR]; + +/***********************************************************************\ +* Per drive structure. * +* N per controller (presently 2) (DRVS_PER_CTLR) * +\***********************************************************************/ +struct fd_data { + struct fdc_data *fdc; + int fdu; /* this unit number */ + int fdsu; /* this units number on this controller */ + int type; /* Drive type (HD, DD */ + struct fd_type *ft; /* pointer to the type descriptor */ + int flags; +#define FD_OPEN 0x01 /* it's open */ +#define FD_ACTIVE 0x02 /* it's active */ +#define FD_MOTOR 0x04 /* motor should be on */ +#define FD_MOTOR_WAIT 0x08 /* motor coming up */ + int skip; + int hddrv; + int track; /* where we think the head is */ +} fd_data[NFD]; + +/***********************************************************************\ +* Throughout this file the following conventions will be used: * +* fd is a pointer to the fd_data struct for the drive in question * +* fdc is a pointer to the fdc_data struct for the controller * +* fdu is the floppy drive unit number * +* fdcu is the floppy controller unit number * +* fdsu is the floppy drive unit number on that controller. (sub-unit) * +\***********************************************************************/ +typedef int fdu_t; +typedef int fdcu_t; +typedef int fdsu_t; +typedef struct fd_data *fd_p; +typedef struct fdc_data *fdc_p; + +#define DEVIDLE 0 +#define FINDWORK 1 +#define DOSEEK 2 +#define SEEKCOMPLETE 3 +#define IOCOMPLETE 4 +#define RECALCOMPLETE 5 +#define STARTRECAL 6 +#define RESETCTLR 7 +#define SEEKWAIT 8 +#define RECALWAIT 9 +#define MOTORWAIT 10 +#define IOTIMEDOUT 11 + +#ifdef DEBUG +char *fdstates[] = +{ +"DEVIDLE", +"FINDWORK", +"DOSEEK", +"SEEKCOMPLETE", +"IOCOMPLETE", +"RECALCOMPLETE", +"STARTRECAL", +"RESETCTLR", +"SEEKWAIT", +"RECALWAIT", +"MOTORWAIT", +"IOTIMEDOUT" +}; + + +int fd_debug = 1; +#define TRACE0(arg) if(fd_debug) printf(arg) +#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2) +#else DEBUG +#define TRACE0(arg) +#define TRACE1(arg1,arg2) +#endif DEBUG + +extern int hz; +/* state needed for current transfer */ + +/****************************************************************************/ +/* autoconfiguration stuff */ +/****************************************************************************/ +int fdprobe(), fdattach(), fd_turnoff(); + +struct isa_driver fddriver = { + fdprobe, fdattach, "fd", +}; + +/* + * probe for existance of controller + */ +fdprobe(dev) +struct isa_device *dev; +{ + fdcu_t fdcu = dev->id_unit; + if(fdc_data[fdcu].flags & FDC_ATTACHED) + { + printf("fdc: same unit (%d) used multiple times\n",fdcu); + return 0; + } + + fdc_data[fdcu].baseport = dev->id_iobase; + + /* see if it can handle a command */ + if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0) + { + return(0); + } + out_fdc(fdcu,0xDF); + out_fdc(fdcu,2); + return (IO_FDCSIZE); +} + +/* + * wire controller into system, look for floppy units + */ +fdattach(dev) +struct isa_device *dev; +{ + unsigned fdt,st0, cyl; + int hdr; + fdu_t fdu; + fdcu_t fdcu = dev->id_unit; + fdc_p fdc = fdc_data + fdcu; + fd_p fd; + int fdsu; + + fdc->fdcu = fdcu; + fdc->flags |= FDC_ATTACHED; + fdc->dmachan = dev->id_drq; + fdc->state = DEVIDLE; + + fdt = rtcin(RTC_FDISKETTE); + hdr = 0; + + /* check for each floppy drive */ + for (fdu = (fdcu * DRVS_PER_CTLR),fdsu = 0; + ((fdu < NFD) && (fdsu < DRVS_PER_CTLR)); + fdu++,fdsu++) + { + /* is there a unit? */ + if ((fdt & 0xf0) == RTCFDT_NONE) + continue; + +#ifdef notyet + /* select it */ + fd_turnon1(fdu); + spinwait(1000); /* 1 sec */ + out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */ + out_fdc(fdcu,fdsu); + spinwait(1000); /* 1 sec */ + + /* anything responding */ + out_fdc(fdcu,NE7CMD_SENSEI); + st0 = in_fdc(fdcu); + cyl = in_fdc(fdcu); + if (st0 & 0xd0) + continue; + +#endif + fd_data[fdu].track = -2; + fd_data[fdu].fdc = fdc; + fd_data[fdu].fdsu = fdsu; + /* yes, announce it */ + if (!hdr) + printf(" drives "); + else + printf(", "); + printf("%d: ", fdu); + + + if ((fdt & 0xf0) == RTCFDT_12M) { + printf("1.2M"); + fd_data[fdu].type = 1; + fd_data[fdu].ft = fd_types + 1; + + } + if ((fdt & 0xf0) == RTCFDT_144M) { + printf("1.44M"); + fd_data[fdu].type = 0; + fd_data[fdu].ft = fd_types + 0; + } + + fdt <<= 4; + fd_turnoff(fdu); + hdr = 1; + } + + printf(" %s ",rev); + /* Set transfer to 500kbps */ + outb(fdc->baseport+fdctl,0); /*XXX*/ +} + +int +fdsize(dev) +dev_t dev; +{ + return(0); +} + +/****************************************************************************/ +/* fdstrategy */ +/****************************************************************************/ +fdstrategy(bp) + register struct buf *bp; /* IO operation to perform */ +{ + register struct buf *dp,*dp0,*dp1; + long nblocks,blknum; + int s; + fdcu_t fdcu; + fdu_t fdu; + fdc_p fdc; + fd_p fd; + + fdu = FDUNIT(minor(bp->b_dev)); + fd = &fd_data[fdu]; + fdc = fd->fdc; + fdcu = fdc->fdcu; + /*type = FDTYPE(minor(bp->b_dev));*/ + + if ((fdu >= NFD) || (bp->b_blkno < 0)) { + printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n", + fdu, bp->b_blkno, bp->b_bcount); + pg("fd:error in fdstrategy"); + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR; + goto bad; + } + /* + * Set up block calculations. + */ + blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK; + nblocks = fd->ft->size; + if (blknum + (bp->b_bcount / FDBLK) > nblocks) { + if (blknum == nblocks) { + bp->b_resid = bp->b_bcount; + } else { + bp->b_error = ENOSPC; + bp->b_flags |= B_ERROR; + } + goto bad; + } + bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads); + dp = &(fdc->head); + s = splbio(); + disksort(dp, bp); + untimeout(fd_turnoff,fdu); /* a good idea */ + fdstart(fdcu); + splx(s); + return; + +bad: + biodone(bp); +} + +/****************************************************************************/ +/* motor control stuff */ +/* remember to not deselect the drive we're working on */ +/****************************************************************************/ +set_motor(fdcu_t fdcu, fdu_t fdu, int reset) +{ + int m0,m1; + int selunit; + fd_p fd; + if(fd = fdc_data[fdcu].fd)/* yes an assign! */ + { + selunit = fd->fdsu; + } + else + { + selunit = 0; + } + m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR; + m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR; + outb(fdc_data[fdcu].baseport+fdout, + selunit + | (reset ? 0 : (FDO_FRST|FDO_FDMAEN)) + | (m0 ? FDO_MOEN0 : 0) + | (m1 ? FDO_MOEN1 : 0)); + TRACE1("[0x%x->fdout]",( + selunit + | (reset ? 0 : (FDO_FRST|FDO_FDMAEN)) + | (m0 ? FDO_MOEN0 : 0) + | (m1 ? FDO_MOEN1 : 0))); +} + +fd_turnoff(fdu_t fdu) +{ + fd_p fd = fd_data + fdu; + fd->flags &= ~FD_MOTOR; + set_motor(fd->fdc->fdcu,fd->fdsu,0); +} + +fd_motor_on(fdu_t fdu) +{ + fd_p fd = fd_data + fdu; + fd->flags &= ~FD_MOTOR_WAIT; + if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT)) + { + fd_pseudointr(fd->fdc->fdcu); + } +} + +fd_turnon(fdu_t fdu) +{ + fd_p fd = fd_data + fdu; + if(!(fd->flags & FD_MOTOR)) + { + fd_turnon1(fdu); + fd->flags |= FD_MOTOR_WAIT; + timeout(fd_motor_on,fdu,hz); /* in 1 sec its ok */ + } +} + +fd_turnon1(fdu_t fdu) +{ + fd_p fd = fd_data + fdu; + fd->flags |= FD_MOTOR; + set_motor(fd->fdc->fdcu,fd->fdsu,0); +} + +/****************************************************************************/ +/* fdc in/out */ +/****************************************************************************/ +int +in_fdc(fdcu_t fdcu) +{ + int baseport = fdc_data[fdcu].baseport; + int i, j = 100000; + while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM)) + != (NE7_DIO|NE7_RQM) && j-- > 0) + if (i == NE7_RQM) return -1; + if (j <= 0) + return(-1); +#ifdef DEBUG + i = inb(baseport+fddata); + TRACE1("[fddata->0x%x]",(unsigned char)i); + return(i); +#else + return inb(baseport+fddata); +#endif +} + +out_fdc(fdcu_t fdcu,int x) +{ + int baseport = fdc_data[fdcu].baseport; + int i = 100000; + + while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0); + while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0); + if (i <= 0) return (-1); + outb(baseport+fddata,x); + TRACE1("[0x%x->fddata]",x); + return (0); +} + +static fdopenf; +/****************************************************************************/ +/* fdopen/fdclose */ +/****************************************************************************/ +Fdopen(dev, flags) + dev_t dev; + int flags; +{ + fdu_t fdu = FDUNIT(minor(dev)); + /*int type = FDTYPE(minor(dev));*/ + int s; + + /* check bounds */ + if (fdu >= NFD) return(ENXIO); + /*if (type >= NUMTYPES) return(ENXIO);*/ + fd_data[fdu].flags |= FD_OPEN; + + return 0; +} + +fdclose(dev, flags) + dev_t dev; +{ + fdu_t fdu = FDUNIT(minor(dev)); + fd_data[fdu].flags &= ~FD_OPEN; + return(0); +} + + +/***************************************************************\ +* fdstart * +* We have just queued something.. if the controller is not busy * +* then simulate the case where it has just finished a command * +* So that it (the interrupt routine) looks on the queue for more* +* work to do and picks up what we just added. * +* If the controller is already busy, we need do nothing, as it * +* will pick up our work when the present work completes * +\***************************************************************/ +fdstart(fdcu_t fdcu) +{ + register struct buf *dp,*bp; + int s; + fdu_t fdu; + + s = splbio(); + if(fdc_data[fdcu].state == DEVIDLE) + { + fdintr(fdcu); + } + splx(s); +} + +fd_timeout(fdcu_t fdcu) +{ + fdu_t fdu = fdc_data[fdcu].fdu; + int st0, st3, cyl; + struct buf *dp,*bp; + + dp = &fdc_data[fdcu].head; + bp = dp->b_actf; + + out_fdc(fdcu,NE7CMD_SENSED); + out_fdc(fdcu,fd_data[fdu].hddrv); + st3 = in_fdc(fdcu); + + out_fdc(fdcu,NE7CMD_SENSEI); + st0 = in_fdc(fdcu); + cyl = in_fdc(fdcu); + printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n", + fdu, + st0, + NE7_ST0BITS, + cyl, + st3, + NE7_ST3BITS); + + if (bp) + { + retrier(fdcu); + fdc_data[fdcu].status[0] = 0xc0; + fdc_data[fdcu].state = IOTIMEDOUT; + if( fdc_data[fdcu].retry < 6) + fdc_data[fdcu].retry = 6; + } + else + { + fdc_data[fdcu].fd = (fd_p) 0; + fdc_data[fdcu].fdu = -1; + fdc_data[fdcu].state = DEVIDLE; + } + fd_pseudointr(fdcu); +} + +/* just ensure it has the right spl */ +fd_pseudointr(fdcu_t fdcu) +{ + int s; + s = splbio(); + fdintr(fdcu); + splx(s); +} + +/***********************************************************************\ +* fdintr * +* keep calling the state machine until it returns a 0 * +* ALWAYS called at SPLBIO * +\***********************************************************************/ +fdintr(fdcu_t fdcu) +{ + fdc_p fdc = fdc_data + fdcu; + while(fdstate(fdcu, fdc)); +} + +/***********************************************************************\ +* The controller state machine. * +* if it returns a non zero value, it should be called again immediatly * +\***********************************************************************/ +int fdstate(fdcu_t fdcu, fdc_p fdc) +{ + int read,head,trac,sec,i,s,sectrac,cyl,st0; + unsigned long blknum; + fdu_t fdu = fdc->fdu; + fd_p fd; + register struct buf *dp,*bp; + + dp = &(fdc->head); + bp = dp->b_actf; + if(!bp) + { + /***********************************************\ + * nothing left for this controller to do * + * Force into the IDLE state, * + \***********************************************/ + fdc->state = DEVIDLE; + if(fdc->fd) + { + printf("unexpected valid fd pointer (fdu = %d)\n" + ,fdc->fdu); + fdc->fd = (fd_p) 0; + fdc->fdu = -1; + } + TRACE1("[fdc%d IDLE]",fdcu); + return(0); + } + fdu = FDUNIT(minor(bp->b_dev)); + fd = fd_data + fdu; + if (fdc->fd && (fd != fdc->fd)) + { + printf("confused fd pointers\n"); + } + read = bp->b_flags & B_READ; + TRACE1("fd%d",fdu); + TRACE1("[%s]",fdstates[fdc->state]); + TRACE1("(0x%x)",fd->flags); + untimeout(fd_turnoff, fdu); + timeout(fd_turnoff,fdu,4 * hz); + switch (fdc->state) + { + case DEVIDLE: + case FINDWORK: /* we have found new work */ + fdc->retry = 0; + fd->skip = 0; + fdc->fd = fd; + fdc->fdu = fdu; + /*******************************************************\ + * If the next drive has a motor startup pending, then * + * it will start up in it's own good time * + \*******************************************************/ + if(fd->flags & FD_MOTOR_WAIT) + { + fdc->state = MOTORWAIT; + return(0); /* come back later */ + } + /*******************************************************\ + * Maybe if it's not starting, it SHOULD be starting * + \*******************************************************/ + if (!(fd->flags & FD_MOTOR)) + { + fdc->state = MOTORWAIT; + fd_turnon(fdu); + return(0); + } + else /* at least make sure we are selected */ + { + set_motor(fdcu,fd->fdsu,0); + } + fdc->state = DOSEEK; + break; + case DOSEEK: + if (bp->b_cylin == fd->track) + { + fdc->state = SEEKCOMPLETE; + break; + } + out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */ + out_fdc(fdcu,fd->fdsu); /* Drive number */ + out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac); + fd->track = -2; + fdc->state = SEEKWAIT; + return(0); /* will return later */ + case SEEKWAIT: + /* allow heads to settle */ + timeout(fd_pseudointr,fdcu,hz/50); + fdc->state = SEEKCOMPLETE; + return(0); /* will return later */ + break; + + case SEEKCOMPLETE : /* SEEK DONE, START DMA */ + /* Make sure seek really happened*/ + if(fd->track == -2) + { + int descyl = bp->b_cylin * fd->ft->steptrac; + out_fdc(fdcu,NE7CMD_SENSEI); + i = in_fdc(fdcu); + cyl = in_fdc(fdcu); + if (cyl != descyl) + { + printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", fdu, + descyl, cyl, i, NE7_ST0BITS); + return(retrier(fdcu)); + } + } + + fd->track = bp->b_cylin; + isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip, + FDBLK, fdc->dmachan); + blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK + + fd->skip/FDBLK; + sectrac = fd->ft->sectrac; + sec = blknum % (sectrac * fd->ft->heads); + head = sec / sectrac; + sec = sec % sectrac + 1; +/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu; + + if (read) + { + out_fdc(fdcu,NE7CMD_READ); /* READ */ + } + else + { + out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */ + } + out_fdc(fdcu,head << 2 | fdu); /* head & unit */ + out_fdc(fdcu,fd->track); /* track */ + out_fdc(fdcu,head); + out_fdc(fdcu,sec); /* sector XXX +1? */ + out_fdc(fdcu,fd->ft->secsize); /* sector size */ + out_fdc(fdcu,sectrac); /* sectors/track */ + out_fdc(fdcu,fd->ft->gap); /* gap size */ + out_fdc(fdcu,fd->ft->datalen); /* data length */ + fdc->state = IOCOMPLETE; + timeout(fd_timeout,fdcu,2 * hz); + return(0); /* will return later */ + case IOCOMPLETE: /* IO DONE, post-analyze */ + untimeout(fd_timeout,fdcu); + for(i=0;i<7;i++) + { + fdc->status[i] = in_fdc(fdcu); + } + case IOTIMEDOUT: /*XXX*/ + isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip, + FDBLK, fdc->dmachan); + if (fdc->status[0]&0xF8) + { + return(retrier(fdcu)); + } + /* All OK */ + fd->skip += FDBLK; + if (fd->skip < bp->b_bcount) + { + /* set up next transfer */ + blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK + + fd->skip/FDBLK; + bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads)); + fdc->state = DOSEEK; + } + else + { + /* ALL DONE */ + fd->skip = 0; + bp->b_resid = 0; + dp->b_actf = bp->av_forw; + biodone(bp); + fdc->fd = (fd_p) 0; + fdc->fdu = -1; + fdc->state = FINDWORK; + } + return(1); + case RESETCTLR: + /* Try a reset, keep motor on */ + set_motor(fdcu,fd->fdsu,1); + DELAY(100); + set_motor(fdcu,fd->fdsu,0); + outb(fdc->baseport+fdctl,fd->ft->trans); + TRACE1("[0x%x->fdctl]",fd->ft->trans); + fdc->retry++; + fdc->state = STARTRECAL; + break; + case STARTRECAL: + out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */ + out_fdc(fdcu,0xDF); + out_fdc(fdcu,2); + out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */ + out_fdc(fdcu,fdu); + fdc->state = RECALWAIT; + return(0); /* will return later */ + case RECALWAIT: + /* allow heads to settle */ + timeout(fd_pseudointr,fdcu,hz/30); + fdc->state = RECALCOMPLETE; + return(0); /* will return later */ + case RECALCOMPLETE: + out_fdc(fdcu,NE7CMD_SENSEI); + st0 = in_fdc(fdcu); + cyl = in_fdc(fdcu); + if (cyl != 0) + { + printf("fd%d: recal failed ST0 %b cyl %d\n", fdu, + st0, NE7_ST0BITS, cyl); + return(retrier(fdcu)); + } + fd->track = 0; + /* Seek (probably) necessary */ + fdc->state = DOSEEK; + return(1); /* will return immediatly */ + case MOTORWAIT: + if(fd->flags & FD_MOTOR_WAIT) + { + return(0); /* time's not up yet */ + } + fdc->state = DOSEEK; + return(1); /* will return immediatly */ + default: + printf("Unexpected FD int->"); + out_fdc(fdcu,NE7CMD_SENSEI); + st0 = in_fdc(fdcu); + cyl = in_fdc(fdcu); + printf("ST0 = %lx, PCN = %lx\n",i,sec); + out_fdc(fdcu,0x4A); + out_fdc(fdcu,fd->fdsu); + for(i=0;i<7;i++) { + fdc->status[i] = in_fdc(fdcu); + } + printf("intr status :%lx %lx %lx %lx %lx %lx %lx ", + fdc->status[0], + fdc->status[1], + fdc->status[2], + fdc->status[3], + fdc->status[4], + fdc->status[5], + fdc->status[6] ); + return(0); + } + return(1); /* Come back immediatly to new state */ +} + +retrier(fdcu_t fdcu) +{ + fdc_p fdc = fdc_data + fdcu; + register struct buf *dp,*bp; + + dp = &(fdc->head); + bp = dp->b_actf; + + switch(fdc->retry) + { + case 0: case 1: case 2: + fdc->state = SEEKCOMPLETE; + break; + case 3: case 4: case 5: + fdc->state = STARTRECAL; + break; + case 6: + fdc->state = RESETCTLR; + break; + case 7: + break; + default: + { + printf("fd%d: hard error (ST0 %b ", + fdc->fdu, fdc->status[0], NE7_ST0BITS); + printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS); + printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS); + printf(" ST3 %b ", fdc->status[3], NE7_ST3BITS); + printf("cyl %d hd %d sec %d)\n", + fdc->status[4], fdc->status[5], fdc->status[6]); + } + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + bp->b_resid = bp->b_bcount - fdc->fd->skip; + dp->b_actf = bp->av_forw; + fdc->fd->skip = 0; + biodone(bp); + fdc->state = FINDWORK; + fdc->fd = (fd_p) 0; + fdc->fdu = -1; + return(1); + } + fdc->retry++; + return(1); +} + +#endif + diff --git a/sys/isa/fdreg.h b/sys/isa/fdreg.h new file mode 100644 index 000000000000..948f566dfda8 --- /dev/null +++ b/sys/isa/fdreg.h @@ -0,0 +1,72 @@ +/*- + * 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 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00153 + * -------------------- ----- ---------------------- + * + * 20 Apr 93 Julian Elischer Heavily re worked, see notes below + */ + +/* + * AT floppy controller registers and bitfields + */ + +/* uses NEC765 controller */ +#include "../i386/isa/ic/nec765.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_MOEN0 0x10 /* motor enable drive 0 */ +#define FDO_MOEN1 0x20 /* motor enable drive 1 */ +#define FDO_MOEN2 0x30 /* motor enable drive 2 */ +#define FDO_MOEN3 0x40 /* motor enable drive 3 */ + +#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 */ + + diff --git a/sys/isa/ic/nec765.h b/sys/isa/ic/nec765.h new file mode 100644 index 000000000000..b84b46e799cf --- /dev/null +++ b/sys/isa/ic/nec765.h @@ -0,0 +1,71 @@ +/*- + * 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. + * + * @(#)nec765.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * Nec 765 floppy disc controller definitions + */ + +/* Main status register */ +#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */ +#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */ +#define NE7_CB 0x10 /* Diskette Controller Busy */ +#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */ +#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */ +#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */ + +/* Status register ST0 */ +#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head" + +/* Status register ST1 */ +#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am" + +/* Status register ST2 */ +#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam" + +/* Status register ST3 */ +#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002" + +/* Commands */ +#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit + parameters byte */ +#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */ +#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */ +#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */ +#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */ +#define NE7CMD_RECAL 7 /* recalibrate drive - requires + unit select byte */ +#define NE7CMD_SENSEI 8 /* sense controller interrupt status */ +#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte + and new cyl byte */ diff --git a/sys/isa/ic/ns16550.h b/sys/isa/ic/ns16550.h new file mode 100644 index 000000000000..e20e9aa58a89 --- /dev/null +++ b/sys/isa/ic/ns16550.h @@ -0,0 +1,50 @@ +/*- + * 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. + * + * @(#)ns16550.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * NS16550 UART registers + */ + +#define com_data 0 /* data register (R/W) */ +#define com_dlbl 0 /* divisor latch low (W) */ +#define com_dlbh 1 /* divisor latch high (W) */ +#define com_ier 1 /* interrupt enable (W) */ +#define com_iir 2 /* interrupt identification (R) */ +#define com_fifo 2 /* FIFO control (W) */ +#define com_lctl 3 /* line control register (R/W) */ +#define com_cfcr 3 /* line control register (R/W) */ +#define com_mcr 4 /* modem control register (R/W) */ +#define com_lsr 5 /* line status register (R/W) */ +#define com_msr 6 /* modem status register (R/W) */ diff --git a/sys/isa/rtc.h b/sys/isa/rtc.h new file mode 100644 index 000000000000..2de060db24c1 --- /dev/null +++ b/sys/isa/rtc.h @@ -0,0 +1,85 @@ +/*- + * 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. + * + * @(#)rtc.h 7.1 (Berkeley) 5/12/91 + */ + +/* + * RTC Register locations + */ + +#define RTC_SEC 0x00 /* seconds */ +#define RTC_SECALRM 0x01 /* seconds alarm */ +#define RTC_MIN 0x02 /* minutes */ +#define RTC_MINALRM 0x03 /* minutes alarm */ +#define RTC_HRS 0x04 /* hours */ +#define RTC_HRSALRM 0x05 /* hours alarm */ +#define RTC_WDAY 0x06 /* week day */ +#define RTC_DAY 0x07 /* day of month */ +#define RTC_MONTH 0x08 /* month of year */ +#define RTC_YEAR 0x09 /* month of year */ +#define RTC_STATUSA 0x0a /* status register A */ +#define RTCSA_TUP 0x80 /* time update, don't look now */ + +#define RTC_STATUSB 0x0b /* status register B */ + +#define RTC_INTR 0x0c /* status register C (R) interrupt source */ +#define RTCIR_UPDATE 0x10 /* update intr */ +#define RTCIR_ALARM 0x20 /* alarm intr */ +#define RTCIR_PERIOD 0x40 /* periodic intr */ +#define RTCIR_INT 0x80 /* interrupt output signal */ + +#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */ +#define RTCSD_PWR 0x80 /* clock lost power */ + +#define RTC_DIAG 0x0e /* status register E - bios diagnostic */ +#define RTCDG_BITS "\020\010clock_battery\007ROM_cksum\006config_unit\005memory_size\004fixed_disk\003invalid_time" + +#define RTC_RESET 0x0f /* status register F - reset code byte */ +#define RTCRS_RST 0x00 /* normal reset */ +#define RTCRS_LOAD 0x04 /* load system */ + +#define RTC_FDISKETTE 0x10 /* diskette drive type in upper/lower nibble */ +#define RTCFDT_NONE 0 /* none present */ +#define RTCFDT_360K 0x10 /* 360K */ +#define RTCFDT_12M 0x20 /* 1.2M */ +#define RTCFDT_144M 0x40 /* 1.44M */ + +#define RTC_BASELO 0x15 /* low byte of basemem size */ +#define RTC_BASEHI 0x16 /* high byte of basemem size */ +#define RTC_EXTLO 0x17 /* low byte of extended mem size */ +#define RTC_EXTHI 0x18 /* low byte of extended mem size */ + +#define RTC_CENTURY 0x32 /* current century - please increment in Dec99*/ diff --git a/sys/isa/sio.c b/sys/isa/sio.c new file mode 100644 index 000000000000..38503fd783bb --- /dev/null +++ b/sys/isa/sio.c @@ -0,0 +1,1721 @@ +/*- + * 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. + * + * @(#)sio.c 7.5 (Berkeley) 5/16/91 + * + * 27 May 93 Bruce Evans From com-0.2 package, fast interrupt + * com port driver. + * 27 May 93 Guido van Rooij Ported in Chris Demetriou's BIDIR + * code, add multiport support. + * 27 May 93 Rodney W. Grimes I then renamed it to sio.c for putting + * into the patch kit. Added in sioselect + * from com.c. Added port 4 support. + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/isa/RCS/com.c,v 1.2 92/01/21 14:34:11 william Exp $"; + +#include "sio.h" +#if NSIO > 0 +/* + * COM driver, based on HP dca driver. + * Mostly rewritten to use pseudo-DMA. + * Works for National Semiconductor NS8250-NS16550AF UARTs. + */ +#include "param.h" +#include "systm.h" +#include "ioctl.h" +#include "tty.h" +#include "proc.h" +#include "user.h" +#include "conf.h" +#include "file.h" +#include "uio.h" +#include "kernel.h" +#include "syslog.h" + +#include "i386/isa/isa.h" +#include "i386/isa/isa_device.h" +#include "i386/isa/comreg.h" +#include "i386/isa/ic/ns16550.h" + +#undef CRTS_IFLOW +#define CRTS_IFLOW CRTSCTS /* XXX, CCTS_OFLOW = CRTSCTS already */ +#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ +#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE) +#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8) +#define RS_IBUFSIZE 256 +#define TS_RTSBLOCK TS_TBLOCK /* XXX */ +#define TTY_BI TTY_FE /* XXX */ +#define TTY_OE TTY_PE /* XXX */ +#ifndef COM_BIDIR +#define UNIT(x) (minor(x)) /* XXX */ +#else /* COM_BIDIR */ +#define COM_UNITMASK 0x7f +#define COM_CALLOUTMASK 0x80 + +#define UNIT(x) (minor(x) & COM_UNITMASK) +#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK) +#endif /* COM_BIDIR */ + +#ifdef COM_MULTIPORT +/* checks in flags for multiport and which is multiport "master chip" + * for a given card + */ +#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01) +#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff) +#endif /* COM_MULTIPORT */ + +#define com_scr 7 /* scratch register for 16450-16550 (R/W) */ +#define schedsoftcom() (ipending |= 1 << 4) /* XXX */ + +/* + * Input buffer watermarks. + * The external device is asked to stop sending when the buffer exactly reaches + * high water, or when the high level requests it. + * The high level is notified immediately (rather than at a later clock tick) + * when this watermark is reached. + * The buffer size is chosen so the watermark should almost never be reached. + * The low watermark is invisibly 0 since the buffer is always emptied all at + * once. + */ +#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4) + +/* + * com state bits. + * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher + * than the other bits so that they can be tested as a group without masking + * off the low bits. + * + * The following com and tty flags correspond closely: + * TS_BUSY = CS_BUSY (maintained by comstart() and comflush()) + * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop()) + * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam()) + * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam()) + * TS_FLUSH is not used. + * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. + */ +#define CS_BUSY 0x80 /* output in progress */ +#define CS_TTGO 0x40 /* output not stopped by XOFF */ +#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */ +#define CS_CHECKMSR 1 /* check of MSR scheduled */ +#define CS_CTS_OFLOW 2 /* use CTS output flow control */ +#define CS_ODONE 4 /* output completed */ +#define CS_RTS_IFLOW 8 /* use RTS input flow control */ + +static char *error_desc[] = { +#define CE_OVERRUN 0 + "silo overflow", +#define CE_INTERRUPT_BUF_OVERFLOW 1 + "interrupt-level buffer overflow", +#define CE_TTY_BUF_OVERFLOW 2 + "tty-level buffer overflow", +}; + +#define CE_NTYPES 3 +#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum]) + +/* types. XXX - should be elsewhere */ +typedef u_int Port_t; /* hardware port */ +typedef int Bool_t; /* promoted boolean */ +typedef u_char bool_t; /* boolean */ + +/* com device structure */ +struct com_s { + u_char state; /* miscellaneous flag bits */ + u_char cfcr_image; /* copy of value written to CFCR */ + bool_t hasfifo; /* nonzero for 16550 UARTs */ + u_char mcr_image; /* copy of value written to MCR */ + bool_t softDCD; /* nonzero for faked carrier detect */ +#ifdef COM_BIDIR + bool_t bidir; /* is this unit bidirectional? */ + bool_t active; /* is the port active _at all_? */ + bool_t active_in; /* is the incoming port in use? */ + bool_t active_out; /* is the outgoing port in use? */ +#endif /* COM_BIDIR */ +#ifdef COM_MULTIPORT + bool_t multiport; /* is this unit part of a multiport device? */ +#endif /* COM_MULTIPORT */ + + /* + * The high level of the driver never reads status registers directly + * because there would be too many side effects to handle conveniently. + * Instead, it reads copies of the registers stored here by the + * interrupt handler. + */ + u_char last_modem_status; /* last MSR read by intr handler */ + u_char prev_modem_status; /* last MSR handled by high level */ + + u_char *ibuf; /* start of input buffer */ + u_char *ibufend; /* end of input buffer */ + u_char *ihighwater; /* threshold in input buffer */ + u_char *iptr; /* next free spot in input buffer */ + + u_char *obufend; /* end of output buffer */ + int ocount; /* original count for current output */ + u_char *optr; /* next char to output */ + + Port_t data_port; /* i/o ports */ + Port_t int_id_port; + Port_t iobase; + Port_t modem_ctl_port; + Port_t line_status_port; + Port_t modem_status_port; + + struct tty *tp; /* cross reference */ + + u_long bytes_in; /* statistics */ + u_long bytes_out; + u_int delta_error_counts[CE_NTYPES]; + u_int error_counts[CE_NTYPES]; + + /* + * Ping-pong input buffers. The extra factor of 2 in the sizes is + * to allow for an error byte for each input byte. + */ +#define CE_INPUT_OFFSET RS_IBUFSIZE + u_char ibuf1[2 * RS_IBUFSIZE]; + u_char ibuf2[2 * RS_IBUFSIZE]; +}; + + +/* + * These functions in the com module ought to be declared (with a prototype) + * in a com-driver system header. The void ones may need to be int to match + * ancient devswitch declarations, but they don't actually return anything. + */ +#define Dev_t int /* promoted dev_t */ +struct consdev; + +int sioclose __P((Dev_t dev, int fflag, int devtype, + struct proc *p)); +void siointr __P((int unit)); +#ifdef COM_MULTIPORT +bool_t comintr1 __P((struct com_s *com)); +#endif /* COM_MULTIPORT */ +int sioioctl __P((Dev_t dev, int cmd, caddr_t data, + int fflag, struct proc *p)); +int siocngetc __P((Dev_t dev)); +void siocninit __P((struct consdev *cp)); +void siocnprobe __P((struct consdev *cp)); +void siocnputc __P((Dev_t dev, int c)); +int sioopen __P((Dev_t dev, int oflags, int devtype, + struct proc *p)); +/* + * sioopen gets compared to the d_open entry in struct cdevsw. d_open and + * other functions are declared in <sys/conf.h> with short types like dev_t + * in the prototype. Such declarations are broken because they vary with + * __P (significantly in theory - the compiler is allowed to push a short + * arg if it has seen the prototype; insignificantly in practice - gcc + * doesn't push short args and it would be slower on 386's to do so). + * + * Also, most of the device switch functions are still declared old-style + * so they take a Dev_t arg and shorten it to a dev_t. It would be simpler + * and faster if dev_t's were always promoted (to ints or whatever) as + * early as possible. + * + * Until <sys/conf.h> is fixed, we cast sioopen to the following `wrong' type + * when comparing it to the d_open entry just to avoid compiler warnings. + */ +typedef int (*bogus_open_t) __P((dev_t dev, int oflags, int devtype, + struct proc *p)); +int sioread __P((Dev_t dev, struct uio *uio, int ioflag)); +void siostop __P((struct tty *tp, int rw)); +int siowrite __P((Dev_t dev, struct uio *uio, int ioflag)); +void softsio0 __P((void)); +void softsio1 __P((void)); +void softsio2 __P((void)); +void softsio3 __P((void)); +void softsio4 __P((void)); +void softsio5 __P((void)); +void softsio6 __P((void)); +void softsio7 __P((void)); +void softsio8 __P((void)); + +static int sioattach __P((struct isa_device *dev)); +static void comflush __P((struct com_s *com)); +static void comhardclose __P((struct com_s *com)); +static void cominit __P((int unit, int rate)); +static int commctl __P((struct com_s *com, int bits, int how)); +static int comparam __P((struct tty *tp, struct termios *t)); +static int sioprobe __P((struct isa_device *dev)); +static void compoll __P((void)); +static int comstart __P((struct tty *tp)); +static void comwakeup __P((void)); + +/* table and macro for fast conversion from a unit number to its com struct */ +static struct com_s *p_com_addr[NSIO]; +#define com_addr(unit) (p_com_addr[unit]) + +static struct com_s com_structs[NSIO]; + +struct isa_driver siodriver = { + sioprobe, sioattach, "sio" +}; + +#ifdef COMCONSOLE +static int comconsole = COMCONSOLE; +#else +static int comconsole = -1; +#endif +static bool_t comconsinit; +static speed_t comdefaultrate = TTYDEF_SPEED; +static u_int com_events; /* input chars + weighted output completions */ +static int commajor; +struct tty sio_tty[NSIO]; +extern struct tty *constty; +extern u_int ipending; /* XXX */ +extern int tk_nin; /* XXX */ +extern int tk_rawcc; /* XXX */ + +#ifdef KGDB +#include "machine/remote-sl.h" + +extern int kgdb_dev; +extern int kgdb_rate; +extern int kgdb_debug_init; +#endif + +static struct speedtab comspeedtab[] = { + 0, 0, + 50, COMBRD(50), + 75, COMBRD(75), + 110, COMBRD(110), + 134, COMBRD(134), + 150, COMBRD(150), + 200, COMBRD(200), + 300, COMBRD(300), + 600, COMBRD(600), + 1200, COMBRD(1200), + 1800, COMBRD(1800), + 2400, COMBRD(2400), + 4800, COMBRD(4800), + 9600, COMBRD(9600), + 19200, COMBRD(19200), + 38400, COMBRD(38400), + 57600, COMBRD(57600), + 115200, COMBRD(115200), + -1, -1 +}; + +/* XXX - configure this list */ +static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, }; + +static int +sioprobe(dev) + struct isa_device *dev; +{ + static bool_t already_init; + Port_t *com_ptr; + Port_t iobase; + int result; + + if (!already_init) { + /* + * Turn off MCR_IENABLE for all likely serial ports. An unused + * port with its MCR_IENABLE gate open will inhibit interrupts + * from any used port that shares the interrupt vector. + */ + for (com_ptr = likely_com_ports; + com_ptr < &likely_com_ports[sizeof likely_com_ports + / sizeof likely_com_ports[0]]; + ++com_ptr) + outb(*com_ptr + com_mcr, 0); + already_init = TRUE; + } + iobase = dev->id_iobase; + result = 1; + + /* + * We don't want to get actual interrupts, just masked ones. + * Interrupts from this line should already be masked in the ICU, + * but mask them in the processor as well in case there are some + * (misconfigured) shared interrupts. + */ + disable_intr(); + + /* + * Enable output interrupts (only) and check the following: + * o the CFCR, IER and MCR in UART hold the values written to them + * (the values happen to be all distinct - this is good for + * avoiding false positive tests from bus echoes). + * o an output interrupt is generated and its vector is correct. + * o the interrupt goes away when the IIR in the UART is read. + */ + outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */ + outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */ + outb(iobase + com_ier, 0); /* ensure edge on next intr */ + outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */ + if ( inb(iobase + com_cfcr) != CFCR_8BITS + || inb(iobase + com_ier) != IER_ETXRDY + || inb(iobase + com_mcr) != MCR_IENABLE + || !isa_irq_pending(dev) + || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY + || isa_irq_pending(dev) + || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND) + result = 0; + + /* + * Turn off all device interrupts and check that they go off properly. + * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to + * the ICU input. Closing the gate would give a floating ICU input + * (unless there is another device driving at) and spurious interrupts. + * (On the system that this was first tested on, the input floats high + * and gives a (masked) interrupt as soon as the gate is closed.) + */ + outb(iobase + com_ier, 0); + outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */ + if ( inb(iobase + com_ier) != 0 + || isa_irq_pending(dev) + || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND) + result = 0; + + enable_intr(); + + return (result); +} + +static int /* XXX - should be void */ +sioattach(isdp) + struct isa_device *isdp; +{ + struct com_s *com; + static bool_t comwakeup_started = FALSE; + Port_t iobase; + int s; + u_char scr; + u_char scr1; + u_char scr2; + int unit; + + iobase = isdp->id_iobase; + unit = isdp->id_unit; + if (unit == comconsole) + DELAY(1000); /* XXX */ + s = spltty(); + + /* + * sioprobe() has initialized the device registers as follows: + * o cfcr = CFCR_8BITS. + * It is most important that CFCR_DLAB is off, so that the + * data port is not hidden when we enable interrupts. + * o ier = 0. + * Interrupts are only enabled when the line is open. + * o mcr = MCR_IENABLE. + * Keeping MCR_DTR and MCR_RTS off might stop the external + * device from sending before we are ready. + */ + + com = &com_structs[unit]; + com->cfcr_image = CFCR_8BITS; + com->mcr_image = MCR_IENABLE; +#if 0 + com->softDCD = TRUE; +#endif + com->iptr = com->ibuf = com->ibuf1; + com->ibufend = com->ibuf1 + RS_IBUFSIZE; + com->ihighwater = com->ibuf1 + RS_IHIGHWATER; + com->iobase = iobase; + com->data_port = iobase + com_data; + com->int_id_port = iobase + com_iir; + com->modem_ctl_port = iobase + com_mcr; + com->line_status_port = iobase + com_lsr; + com->modem_status_port = iobase + com_msr; + com->tp = &sio_tty[unit]; +#ifdef COM_BIDIR + /* + * if bidirectional ports possible, clear the bidir port info; + */ + com->bidir = FALSE; + com->active = FALSE; + com->active_in = com->active_out = FALSE; +#endif /* COM_BIDIR */ + + /* attempt to determine UART type */ + scr = inb(iobase + com_scr); + outb(iobase + com_scr, 0xa5); + scr1 = inb(iobase + com_scr); + outb(iobase + com_scr, 0x5a); + scr2 = inb(iobase + com_scr); + outb(iobase + com_scr, scr); + if (scr1 != 0xa5 || scr2 != 0x5a) + printf(" <8250>"); + else { + outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14); + DELAY(100); + switch (inb(iobase + com_iir) & IIR_FIFO_MASK) { + case FIFO_TRIGGER_1: + printf(" <16450>"); + break; + case FIFO_TRIGGER_4: + printf(" <16450?>"); + break; + case FIFO_TRIGGER_8: + printf(" <16550?>"); + break; + case FIFO_TRIGGER_14: + com->hasfifo = TRUE; + printf(" <16550A>"); + break; + } + outb(iobase + com_fifo, 0); + } +#ifdef COM_MULTIPORT + if (COM_ISMULTIPORT(isdp)) { + struct isa_device *masterdev; + + com->multiport = TRUE; + printf(" (multiport)"); + + /* set the master's common-interrupt-enable reg., + * as appropriate. YYY See your manual + */ + /* enable only common interrupt for port */ + outb(iobase + com_mcr, 0); + + masterdev = find_isadev(isa_devtab_tty, &siodriver, + COM_MPMASTER(isdp)); + outb(masterdev->id_iobase+com_scr, 0x80); + } + else + com->multiport = FALSE; +#endif /* COM_MULTIPORT */ + +#ifdef KGDB + if (kgdb_dev == makedev(commajor, unit)) { + if (comconsole == unit) + kgdb_dev = -1; /* can't debug over console port */ + else { + cominit(unit, kgdb_rate); + if (kgdb_debug_init) { + /* + * Print prefix of device name, + * let kgdb_connect print the rest. + */ + printf("com%d: ", unit); + kgdb_connect(1); + } + else + printf("com%d: kgdb enabled\n", unit); + } + } +#endif + + /* + * Need to reset baud rate, etc. of next print so reset comconsinit. + * Also make sure console is always "hardwired" + */ + if (unit == comconsole) { + comconsinit = FALSE; + com->softDCD = TRUE; + } + + com_addr(unit) = com; + + splx(s); + + if (!comwakeup_started) { + comwakeup(); + comwakeup_started = TRUE; + } + + return (1); +} + +/* ARGSUSED */ +int +sioopen(dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + struct com_s *com; + int error = 0; + Port_t iobase; + int s; + struct tty *tp; + int unit = UNIT(dev); +#ifdef COM_BIDIR + bool_t callout = CALLOUT(dev); +#endif /* COM_BIDIR */ + if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL) + return (ENXIO); +#ifdef COM_BIDIR + /* if it's a callout device, and bidir not possible on that dev, die */ + if (callout && !(com->bidir)) + return (ENXIO); +#endif /* COM_BIDIR */ + + tp = com->tp; + s = spltty(); + +#ifdef COM_BIDIR + +bidir_open_top: + /* if it's bidirectional, we've gotta deal with it... */ + if (com->bidir) { + if (callout) { + if (com->active_in) { + /* it's busy. die */ + splx(s); + return (EBUSY); + } else { + /* it's ours. lock it down, and set it up */ + com->active_out = TRUE; + com->softDCD = TRUE; + } + } else { + if (com->active_out) { + /* it's busy, outgoing. wait, if possible */ + if (flag & O_NONBLOCK) { + /* can't wait; bail */ + splx(s); + return (EBUSY); + } else { + /* wait for it... */ + error = tsleep(&com->active_out, + TTIPRI|PCATCH, + "comoth", + 0); + /* if there was an error, take off. */ + if (error != 0) { + splx(s); + return (error); + } + /* else take it from the top */ + goto bidir_open_top; + } + } else if (com->last_modem_status & MSR_DCD) { + /* there's a carrier on the line; we win */ + com->active_in = TRUE; + com->softDCD = FALSE; + } else { + /* there is no carrier on the line */ + if (flag & O_NONBLOCK) { + /* can't wait; let it open */ + com->active_in = TRUE; + com->softDCD = FALSE; + } else { + /* put DTR & RTS up */ + /* NOTE: cgd'sdriver used the ier register + * to enable/disable interrupts. This one + * uses both ier and IENABLE in the mcr. + */ + (void) commctl(com, MCR_DTR | MCR_RTS, DMSET); + outb(com->iobase + com_ier, IER_EMSC); + /* wait for it... */ + error = tsleep(&com->active_in, + TTIPRI|PCATCH, + "comdcd", + 0); + + /* if not active, turn DTR & RTS off */ + if (!com->active) + (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC); + + /* if there was an error, take off. */ + if (error != 0) { + splx(s); + return (error); + } + /* else take it from the top */ + goto bidir_open_top; + } + } + } + } + + com->active = TRUE; +#endif /* COM_BIDIR */ + + tp->t_oproc = comstart; + tp->t_param = comparam; + tp->t_dev = dev; + if (!(tp->t_state & TS_ISOPEN)) { + tp->t_state |= TS_WOPEN; + ttychars(tp); + if (tp->t_ispeed == 0) { + /* + * We no longer use the flags from <sys/ttydefaults.h> + * since those are only relevant for logins. It's + * important to have echo off initially so that the + * line doesn't start blathering before the echo flag + * can be turned off. It's useful to have clocal on + * initially so that "stty changed-defaults </dev/comx" + * doesn't hang waiting for carrier. + */ + tp->t_iflag = 0; + tp->t_oflag = 0; + tp->t_cflag = CREAD | CS8 | CLOCAL; + tp->t_lflag = 0; + tp->t_ispeed = tp->t_ospeed = comdefaultrate; + } + (void) commctl(com, MCR_DTR | MCR_RTS, DMSET); + error = comparam(tp, &tp->t_termios); + if (error != 0) + goto out; + ttsetwater(tp); + iobase = com->iobase; + disable_intr(); + if (com->hasfifo) + /* (re)enable and drain FIFO */ + outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14 + | FIFO_RCV_RST | FIFO_XMT_RST); + (void) inb(com->line_status_port); + (void) inb(com->data_port); + com->last_modem_status = + com->prev_modem_status = inb(com->modem_status_port); + outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS + | IER_EMSC); + enable_intr(); + if (com->softDCD || com->prev_modem_status & MSR_DCD) + tp->t_state |= TS_CARR_ON; + } + else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { + splx(s); + return (EBUSY); + } + while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) +#ifdef COM_BIDIR + /* We went through a lot of trouble to open it, + * but it's certain we have a carrier now, so + * don't spend any time on it now. + */ + && !(com->bidir) +#endif /* COM_BIDIR */ + && !(tp->t_state & TS_CARR_ON)) { + tp->t_state |= TS_WOPEN; + error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, + ttopen, 0); + if (error != 0) + break; + } +out: + splx(s); + if (error == 0) + error = (*linesw[tp->t_line].l_open)(dev, tp); + +#ifdef COM_BIDIR + /* wakeup sleepers */ + wakeup((caddr_t) &com->active_in); +#endif /* COM_BIDIR */ + + /* + * XXX - the next step was once not done, so interrupts, DTR and RTS + * remainded hot if the process was killed while it was sleeping + * waiting for carrier. Now there is the opposite problem. If several + * processes are sleeping waiting for carrier on the same line and one + * is killed, interrupts are turned off so the other processes will + * never see the carrier rise. + */ + if (error != 0 && !(tp->t_state & TS_ISOPEN)) +{ + comhardclose(com); +} + tp->t_state &= ~TS_WOPEN; + + return (error); +} + +/*ARGSUSED*/ +int +sioclose(dev, flag, mode, p) + dev_t dev; + int flag; + int mode; + struct proc *p; +{ + struct com_s *com; + struct tty *tp; + + com = com_addr(UNIT(dev)); + tp = com->tp; + (*linesw[tp->t_line].l_close)(tp, flag); + comhardclose(com); + ttyclose(tp); + return (0); +} + +void +comhardclose(com) + struct com_s *com; +{ + Port_t iobase; + int s; + struct tty *tp; + + s = spltty(); + iobase = com->iobase; + outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); +#ifdef KGDB + /* do not disable interrupts if debugging */ + if (kgdb_dev != makedev(commajor, com - &com_structs[0])) +#endif + outb(iobase + com_ier, 0); + tp = com->tp; + if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN + || !(tp->t_state & TS_ISOPEN)) + (void) commctl(com, 0, DMSET); +#ifdef COM_BIDIR + com->active = com->active_in = com->active_out = FALSE; + com->softDCD = FALSE; + + /* wakeup sleepers who are waiting for out to finish */ + wakeup((caddr_t) &com->active_out); +#endif /* COM_BIDIR */ + + splx(s); +} + +int +sioread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct tty *tp = com_addr(UNIT(dev))->tp; + + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +int +siowrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + int unit = UNIT(dev); + struct tty *tp = com_addr(unit)->tp; + + /* + * (XXX) We disallow virtual consoles if the physical console is + * a serial port. This is in case there is a display attached that + * is not the console. In that situation we don't need/want the X + * server taking over the console. + */ + if (constty && unit == comconsole) + constty = NULL; + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +void +siointr(unit) + int unit; +{ + struct com_s *com; +#ifndef COM_MULTIPORT + u_char line_status; + u_char modem_status; + u_char *ioptr; + u_char recv_data; + + com = com_addr(unit); +#else /* COM_MULTIPORT */ + int i; + bool_t donesomething; + + do { + donesomething = FALSE; + for(i=0;i<NSIO;i++) { + com=com_addr(i); + if(com != NULL) { + /* XXX When siointr is called + * to start output, maybe + * it should be changed to a + * call to comintr1. Doesn't + * seem a good idea: interrupts + * are disabled all the time. + */ +enable_intr(); +disable_intr(); + donesomething = comintr1(com); + } + } + } while (donesomething); + return; +} + +bool_t +comintr1(struct com_s *com) +{ + u_char line_status; + u_char modem_status; + u_char *ioptr; + u_char recv_data; + bool_t donesomething; + + donesomething = FALSE; +#endif /* COM_MULTIPORT */ + + while (TRUE) { + line_status = inb(com->line_status_port); + + /* input event? (check first to help avoid overruns) */ + while (line_status & LSR_RCV_MASK) { + /* break/unnattached error bits or real input? */ +#ifdef COM_MULTIPORT + donesomething = TRUE; +#endif /* COM_MULTIPORT */ + if (!(line_status & LSR_RXRDY)) + recv_data = 0; + else + recv_data = inb(com->data_port); + ++com->bytes_in; +#ifdef KGDB + /* trap into kgdb? (XXX - needs testing and optim) */ + if (recv_data == FRAME_END + && !(com->tp->t_state & TS_ISOPEN) + && kgdb_dev == makedev(commajor, unit)) { + kgdb_connect(0); + continue; + } +#endif /* KGDB */ + ioptr = com->iptr; + if (ioptr >= com->ibufend) + CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW); + else { + ++com_events; + ioptr[0] = recv_data; + ioptr[CE_INPUT_OFFSET] = line_status; + com->iptr = ++ioptr; + if (ioptr == com->ihighwater + && com->state & CS_RTS_IFLOW) + outb(com->modem_ctl_port, + com->mcr_image &= ~MCR_RTS); + } + + /* + * "& 0x7F" is to avoid the gcc-1.40 generating a slow + * jump from the top of the loop to here + */ + line_status = inb(com->line_status_port) & 0x7F; + } + + /* modem status change? (always check before doing output) */ + modem_status = inb(com->modem_status_port); + if (modem_status != com->last_modem_status) { + /* + * Schedule high level to handle DCD changes. Note + * that we don't use the delta bits anywhere. Some + * UARTs mess them up, and it's easy to remember the + * previous bits and calculate the delta. + */ +#ifdef COM_MULTIPORT + donesomething = TRUE; +#endif /* COM_MULTIPORT */ + com->last_modem_status = modem_status; + if (!(com->state & CS_CHECKMSR)) { + com_events += LOTS_OF_EVENTS; + com->state |= CS_CHECKMSR; + schedsoftcom(); + } + + /* handle CTS change immediately for crisp flow ctl */ + if (com->state & CS_CTS_OFLOW) { + if (modem_status & MSR_CTS) + com->state |= CS_ODEVREADY; + else + com->state &= ~CS_ODEVREADY; + } + } + + /* output queued and everything ready? */ + if (line_status & LSR_TXRDY + && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) { +#ifdef COM_MULTIPORT + donesomething = TRUE; +#endif /* COM_MULTIPORT */ + ioptr = com->optr; + outb(com->data_port, *ioptr); + ++com->bytes_out; + com->optr = ++ioptr; + if (ioptr >= com->obufend) { + /* output just completed */ + com_events += LOTS_OF_EVENTS; + com->state ^= (CS_ODONE | CS_BUSY); + schedsoftcom(); /* handle at high level ASAP */ + } + } + + /* finished? */ + if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND) +#ifdef COM_MULTIPORT + return (donesomething); +#else + return; +#endif /* COM_MULTIPORT */ + } +} + +int +sioioctl(dev, cmd, data, flag, p) + dev_t dev; + int cmd; + caddr_t data; + int flag; + struct proc *p; +{ + struct com_s *com; + int error; + Port_t iobase; + int s; + struct tty *tp; + + com = com_addr(UNIT(dev)); + tp = com->tp; + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); + if (error >= 0) + return (error); + error = ttioctl(tp, cmd, data, flag); + if (error >= 0) + return (error); + + iobase = com->iobase; + s = spltty(); + switch (cmd) { + case TIOCSBRK: + outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK); + break; + case TIOCCBRK: + outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); + break; + case TIOCSDTR: + (void) commctl(com, MCR_DTR | MCR_RTS, DMBIS); + break; + case TIOCCDTR: + (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC); + break; + case TIOCMSET: + (void) commctl(com, *(int *)data, DMSET); + break; + case TIOCMBIS: + (void) commctl(com, *(int *)data, DMBIS); + break; + case TIOCMBIC: + (void) commctl(com, *(int *)data, DMBIC); + break; + case TIOCMGET: + *(int *)data = commctl(com, 0, DMGET); + break; +#ifdef COM_BIDIR + case TIOCMSBIDIR: + /* must be root to set bidir. capability */ + if (p->p_ucred->cr_uid != 0) + return(EPERM); + + /* if it's the console, can't do it */ + if (UNIT(dev) == comconsole) + return(ENOTTY); + + /* can't do the next, for obvious reasons... + * but there are problems to be looked at... + */ + + /* if the port is active, don't do it */ + /* if (com->active) + return(EBUSY); */ + + com->bidir = *(int *)data; + break; + case TIOCMGBIDIR: + *(int *)data = com->bidir; + break; +#endif /* COM_BIDIR */ + default: + splx(s); + return (ENOTTY); + } + splx(s); + return (0); +} + +/* cancel pending output */ +static void +comflush(com) + struct com_s *com; +{ + struct ringb *rbp; + + disable_intr(); + if (com->state & CS_ODONE) + com_events -= LOTS_OF_EVENTS; + com->state &= ~(CS_ODONE | CS_BUSY); + enable_intr(); + rbp = &com->tp->t_out; + rbp->rb_hd += com->ocount; + rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd); + com->ocount = 0; + com->tp->t_state &= ~TS_BUSY; +} + +static void +compoll() +{ + static bool_t awake = FALSE; + struct com_s *com; + int s; + int unit; + + if (com_events == 0) + return; + disable_intr(); + if (awake) { + enable_intr(); + return; + } + awake = TRUE; + enable_intr(); + s = spltty(); +repeat: + for (unit = 0; unit < NSIO; ++unit) { + u_char *buf; + u_char *ibuf; + int incc; + struct tty *tp; + + com = com_addr(unit); + if (com == NULL) + continue; + tp = com->tp; + + /* switch the role of the low-level input buffers */ + if (com->iptr == (ibuf = com->ibuf)) + incc = 0; + else { + buf = ibuf; + disable_intr(); + incc = com->iptr - buf; + com_events -= incc; + if (ibuf == com->ibuf1) + ibuf = com->ibuf2; + else + ibuf = com->ibuf1; + com->ibufend = ibuf + RS_IBUFSIZE; + com->ihighwater = ibuf + RS_IHIGHWATER; + com->iptr = ibuf; + + /* + * There is now room for another low-level buffer full + * of input, so enable RTS if it is now disabled and + * there is room in the high-level buffer. + */ + if (!(com->mcr_image & MCR_RTS) + && !(tp->t_state & TS_RTSBLOCK)) + outb(com->modem_ctl_port, + com->mcr_image |= MCR_RTS); + enable_intr(); + com->ibuf = ibuf; + } + + if (com->state & CS_CHECKMSR) { + u_char delta_modem_status; + + disable_intr(); + delta_modem_status = com->last_modem_status + ^ com->prev_modem_status; + com->prev_modem_status = com->last_modem_status; + com_events -= LOTS_OF_EVENTS; + com->state &= ~CS_CHECKMSR; + enable_intr(); + if (delta_modem_status & MSR_DCD && + unit != comconsole) { +#ifdef COM_BIDIR + if (com->prev_modem_status & MSR_DCD) { + (*linesw[tp->t_line].l_modem)(tp, 1); + com->softDCD = FALSE; + wakeup((caddr_t) &com->active_in); + } +#else + if (com->prev_modem_status & MSR_DCD) + (*linesw[tp->t_line].l_modem)(tp, 1); +#endif /* COM_BIDIR */ + else if ((*linesw[tp->t_line].l_modem)(tp, 0) + == 0) { + disable_intr(); + outb(com->modem_ctl_port, + com->mcr_image + &= ~(MCR_DTR | MCR_RTS)); + enable_intr(); + } + } + } + + /* XXX */ + if (TRUE) { + u_int delta; + u_int delta_error_counts[CE_NTYPES]; + int errnum; + u_long total; + + disable_intr(); + bcopy(com->delta_error_counts, delta_error_counts, + sizeof delta_error_counts); + bzero(com->delta_error_counts, + sizeof delta_error_counts); + enable_intr(); + for (errnum = 0; errnum < CE_NTYPES; ++errnum) { + delta = delta_error_counts[errnum]; + if (delta != 0) { + total = + com->error_counts[errnum] += delta; + log(LOG_WARNING, + "com%d: %u more %s%s (total %lu)\n", + unit, delta, error_desc[errnum], + delta == 1 ? "" : "s", total); + } + } + } + if (com->state & CS_ODONE) { + comflush(com); + /* XXX - why isn't the table used for t_line == 0? */ + if (tp->t_line != 0) + (*linesw[tp->t_line].l_start)(tp); + else + comstart(tp); + } + if (incc <= 0 || !(tp->t_state & TS_ISOPEN)) + continue; + if (com->state & CS_RTS_IFLOW + && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER + && !(tp->t_state & TS_RTSBLOCK) + /* + * XXX - need RTS flow control for all line disciplines. + * Only have it in standard one now. + */ + && linesw[tp->t_line].l_rint == ttyinput) { + tp->t_state |= TS_RTSBLOCK; + ttstart(tp); + } + /* + * Avoid the grotesquely inefficient lineswitch routine + * (ttyinput) in "raw" mode. It usually takes about 450 + * instructions (that's without canonical processing or echo!). + * slinput is reasonably fast (usually 40 instructions plus + * call overhead). + */ + if (!(tp->t_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP + | IXOFF | IXON)) + && !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG + | PENDIN)) + && !(tp->t_state & (TS_CNTTB | TS_LNCH)) + && linesw[tp->t_line].l_rint == ttyinput) { + tk_nin += incc; + tk_rawcc += incc; + tp->t_rawcc += incc; + com->delta_error_counts[CE_TTY_BUF_OVERFLOW] + += incc - rb_write(&tp->t_raw, (char *) buf, + incc); + ttwakeup(tp); + if (tp->t_state & TS_TTSTOP + && (tp->t_iflag & IXANY + || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { + tp->t_state &= ~TS_TTSTOP; + tp->t_lflag &= ~FLUSHO; + ttstart(tp); + } + } + else { + do { + u_char line_status; + int recv_data; + + line_status = (u_char) buf[CE_INPUT_OFFSET]; + recv_data = (u_char) *buf++; + if (line_status + & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) { + if (line_status & LSR_BI) + recv_data |= TTY_BI; + if (line_status & LSR_FE) + recv_data |= TTY_FE; + if (line_status & LSR_OE) + recv_data |= TTY_OE; + if (line_status & LSR_PE) + recv_data |= TTY_PE; + } + (*linesw[tp->t_line].l_rint)(recv_data, tp); + } while (--incc > 0); + } + if (com_events == 0) + break; + } + if (com_events >= LOTS_OF_EVENTS) + goto repeat; + splx(s); + awake = FALSE; +} + +static int +comparam(tp, t) + struct tty *tp; + struct termios *t; +{ + u_int cfcr; + int cflag; + struct com_s *com; + int divisor; + int error; + Port_t iobase; + int s; + int unit; + + /* check requested parameters */ + divisor = ttspeedtab(t->c_ospeed, comspeedtab); + if (divisor < 0 || t->c_ispeed != 0 && t->c_ispeed != t->c_ospeed) + return (EINVAL); + + /* parameters are OK, convert them to the com struct and the device */ + unit = UNIT(tp->t_dev); + com = com_addr(unit); + iobase = com->iobase; + s = spltty(); + if (divisor == 0) { + (void) commctl(com, 0, DMSET); /* hang up line */ + splx(s); + return (0); + } + cflag = t->c_cflag; + switch (cflag & CSIZE) { + case CS5: + cfcr = CFCR_5BITS; + break; + case CS6: + cfcr = CFCR_6BITS; + break; + case CS7: + cfcr = CFCR_7BITS; + break; + default: + cfcr = CFCR_8BITS; + break; + } + if (cflag & PARENB) { + cfcr |= CFCR_PENAB; + if (!(cflag & PARODD)) + cfcr |= CFCR_PEVEN; + } + if (cflag & CSTOPB) + cfcr |= CFCR_STOPB; + + /* + * Some UARTs lock up if the divisor latch registers are selected + * while the UART is doing output (they refuse to transmit anything + * more until given a hard reset). Fix this by stopping filling + * the device buffers and waiting for them to drain. Reading the + * line status port outside of siointr() might lose some receiver + * error bits, but that is acceptable here. + */ + disable_intr(); + com->state &= ~CS_TTGO; + enable_intr(); + while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) + != (LSR_TSRE | LSR_TXRDY)) { + error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, + "comparam", 1); + if (error != 0 && error != EAGAIN) { + if (!(tp->t_state & TS_TTSTOP)) { + disable_intr(); + com->state |= CS_TTGO; + enable_intr(); + } + splx(s); + return (error); + } + } + + disable_intr(); /* very important while com_data is hidden */ + outb(iobase + com_cfcr, cfcr | CFCR_DLAB); + outb(iobase + com_dlbl, divisor & 0xFF); + outb(iobase + com_dlbh, (u_int) divisor >> 8); + outb(iobase + com_cfcr, com->cfcr_image = cfcr); + if (!(tp->t_state & TS_TTSTOP)) + com->state |= CS_TTGO; + if (cflag & CRTS_IFLOW) + com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */ + else + com->state &= ~CS_RTS_IFLOW; + + /* + * Set up state to handle output flow control. + * XXX - worth handling MDMBUF (DCD) flow control at the lowest level? + * Now has 16+ msec latency, while CTS flow has 50- usec latency. + * Note that DCD flow control stupidly uses the same state flag + * (TS_TTSTOP) as XON/XOFF flow control. + */ + com->state &= ~CS_CTS_OFLOW; + com->state |= CS_ODEVREADY; + if (cflag & CCTS_OFLOW) { + com->state |= CS_CTS_OFLOW; + if (!(com->prev_modem_status & MSR_CTS)) + com->state &= ~CS_ODEVREADY; + } + + enable_intr(); + siointr(unit); /* recover from fiddling with CS_TTGO */ + splx(s); + return (0); +} + +static int /* XXX - should be void */ +comstart(tp) + struct tty *tp; +{ + struct com_s *com; + int s; + int unit; + + unit = UNIT(tp->t_dev); + com = com_addr(unit); + s = spltty(); + disable_intr(); + if (tp->t_state & TS_TTSTOP) + com->state &= ~CS_TTGO; + else + com->state |= CS_TTGO; + if (tp->t_state & TS_RTSBLOCK) { + if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW) + outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); + } + else { + if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater) + outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); + } + enable_intr(); + if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) + goto out; + if (RB_LEN(&tp->t_out) <= tp->t_lowat) { + if (tp->t_state & TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t)&tp->t_out); + } + if (tp->t_wsel) { + selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); + tp->t_wsel = 0; + tp->t_state &= ~TS_WCOLL; + } + } + if (com->ocount != 0) { + disable_intr(); + siointr(unit); + enable_intr(); + } + else if (RB_LEN(&tp->t_out) != 0) { + tp->t_state |= TS_BUSY; + com->ocount = RB_CONTIGGET(&tp->t_out); + disable_intr(); + com->obufend = (com->optr = (u_char *) tp->t_out.rb_hd) + + com->ocount; + com->state |= CS_BUSY; + siointr(unit); /* fake interrupt to start output */ + enable_intr(); + } +out: + splx(s); + return (1); +} + +void +siostop(tp, rw) + struct tty *tp; + int rw; +{ + struct com_s *com; + + com = com_addr(UNIT(tp->t_dev)); + if (rw & FWRITE) + comflush(com); + disable_intr(); + if (tp->t_state & TS_TTSTOP) + com->state &= ~CS_TTGO; + else + com->state |= CS_TTGO; + enable_intr(); +} + +static int +commctl(com, bits, how) + struct com_s *com; + int bits; + int how; +{ + disable_intr(); + switch (how) { + case DMSET: +#ifdef COM_MULTIPORT + /* YYY maybe your card doesn't want IENABLE to be reset? */ + if(com->multiport) + outb(com->modem_ctl_port, + com->mcr_image = bits); + else +#endif /* COM_MULTIPORT */ + outb(com->modem_ctl_port, + com->mcr_image = bits | MCR_IENABLE); + break; + case DMBIS: + outb(com->modem_ctl_port, com->mcr_image |= bits); + break; + case DMBIC: +#ifdef COM_MULTIPORT + /* YYY maybe your card doesn't want IENABLE to be reset? */ + if(com->multiport) + outb(com->modem_ctl_port, + com->mcr_image &= ~(bits)); + else +#endif /* COM_MULTIPORT */ + outb(com->modem_ctl_port, + com->mcr_image &= ~(bits & ~MCR_IENABLE)); + break; + case DMGET: + bits = com->prev_modem_status; + break; + } + enable_intr(); + return (bits); +} + +static void +comwakeup() +{ + struct com_s *com; + int unit; + + timeout((timeout_func_t) comwakeup, (caddr_t) NULL, 1); + if (com_events != 0) + /* schedule compoll() to run when the cpl allows */ + schedsoftcom(); + + /* recover from lost output interrupts */ + for (unit = 0; unit < NSIO; ++unit) { + com = com_addr(unit); + if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) { + disable_intr(); + siointr(unit); + enable_intr(); + } + } +} + +void +softsio0() { compoll(); } + +void +softsio1() { compoll(); } + +void +softsio2() { compoll(); } + +void +softsio3() { compoll(); } + +void +softsio4() { compoll(); } + +void +softsio5() { compoll(); } + +void +softsio6() { compoll(); } + +void +softsio7() { compoll(); } + +void +softsio8() { compoll(); } + +/* + * Following are all routines needed for COM to act as console + * XXX - not tested in this version + * XXX - check that the corresponding serial interrupts are never enabled + */ +#include "i386/i386/cons.h" + +void +siocnprobe(cp) + struct consdev *cp; +{ + int unit; + + /* locate the major number */ + for (commajor = 0; commajor < nchrdev; commajor++) + if (cdevsw[commajor].d_open == (bogus_open_t) sioopen) + break; + + /* XXX: ick */ + unit = CONUNIT; + com_addr(unit) = &com_structs[unit]; + com_addr(unit)->iobase = CONADDR; + + /* make sure hardware exists? XXX */ + + /* initialize required fields */ + cp->cn_dev = makedev(commajor, unit); + cp->cn_tp = &sio_tty[unit]; +#ifdef COMCONSOLE + cp->cn_pri = CN_REMOTE; /* Force a serial port console */ +#else + cp->cn_pri = CN_NORMAL; +#endif +} + +void +siocninit(cp) + struct consdev *cp; +{ + int unit; + + unit = UNIT(cp->cn_dev); + cominit(unit, comdefaultrate); + comconsole = unit; + comconsinit = TRUE; +} + +static void +cominit(unit, rate) + int unit; + int rate; +{ + Port_t iobase; + int s; + + iobase = com_addr(unit)->iobase; + s = splhigh(); + outb(iobase + com_cfcr, CFCR_DLAB); + rate = ttspeedtab(comdefaultrate, comspeedtab); + outb(iobase + com_data, rate & 0xFF); + outb(iobase + com_ier, rate >> 8); + outb(iobase + com_cfcr, CFCR_8BITS); + + /* + * XXX - fishy to enable interrupts and then poll. + * It shouldn't be necessary to ready the iir. + */ + outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); + outb(iobase + com_fifo, + FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); + (void) inb(iobase + com_iir); + splx(s); +} + +int +siocngetc(dev) + dev_t dev; +{ + int c; + Port_t iobase; + int s; + + iobase = com_addr(UNIT(dev))->iobase; + s = splhigh(); + while (!(inb(iobase + com_lsr) & LSR_RXRDY)) + ; + c = inb(iobase + com_data); + (void) inb(iobase + com_iir); + splx(s); + return (c); +} + +void +siocnputc(dev, c) + dev_t dev; + int c; +{ + Port_t iobase; + int s; + int timo; + + iobase = com_addr(UNIT(dev))->iobase; + s = splhigh(); +#ifdef KGDB + if (dev != kgdb_dev) +#endif + if (!comconsinit) { + (void) cominit(UNIT(dev), comdefaultrate); + comconsinit = TRUE; + } + /* wait for any pending transmission to finish */ + timo = 50000; + while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo) + ; + outb(iobase + com_data, c); + /* wait for this transmission to complete */ + timo = 1500000; + while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo) + ; + /* clear any interrupts generated by this transmission */ + (void) inb(iobase + com_iir); + splx(s); +} + +/* + * 10 Feb 93 Jordan K. Hubbard Added select code + * 27 May 93 Rodney W. Grimes Stole the select code from com.c.pl5 + */ + +int +sioselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; +{ + register struct tty *tp = &sio_tty[UNIT(dev)]; + int nread; + int s = spltty(); + struct proc *selp; + + switch (rw) { + + case FREAD: + nread = ttnread(tp); + if (nread > 0 || + ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) + goto win; + if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_RCOLL; + else + tp->t_rsel = p->p_pid; + break; + + case FWRITE: + if (RB_LEN(&tp->t_out) <= tp->t_lowat) + goto win; + if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_WCOLL; + else + tp->t_wsel = p->p_pid; + break; + } + splx(s); + return (0); + win: + splx(s); + return (1); +} + +#endif /* NSIO > 0 */ diff --git a/sys/isa/sioreg.h b/sys/isa/sioreg.h new file mode 100644 index 000000000000..2a626832e87c --- /dev/null +++ b/sys/isa/sioreg.h @@ -0,0 +1,113 @@ +/*- + * 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. + * + * @(#)comreg.h 7.2 (Berkeley) 5/9/91 + */ + + +/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */ +#define COMBRD(x) (1843200 / (16*(x))) + +/* interrupt enable register */ +#define IER_ERXRDY 0x1 +#define IER_ETXRDY 0x2 +#define IER_ERLS 0x4 +#define IER_EMSC 0x8 + +/* interrupt identification register */ +#define IIR_IMASK 0xf +#define IIR_RXTOUT 0xc +#define IIR_RLS 0x6 +#define IIR_RXRDY 0x4 +#define IIR_TXRDY 0x2 +#define IIR_NOPEND 0x1 +#define IIR_MLSC 0x0 +#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */ + +/* fifo control register */ +#define FIFO_ENABLE 0x01 +#define FIFO_RCV_RST 0x02 +#define FIFO_XMT_RST 0x04 +#define FIFO_DMA_MODE 0x08 +#define FIFO_TRIGGER_1 0x00 +#define FIFO_TRIGGER_4 0x40 +#define FIFO_TRIGGER_8 0x80 +#define FIFO_TRIGGER_14 0xc0 + +/* character format control register */ +#define CFCR_DLAB 0x80 +#define CFCR_SBREAK 0x40 +#define CFCR_PZERO 0x30 +#define CFCR_PONE 0x20 +#define CFCR_PEVEN 0x10 +#define CFCR_PODD 0x00 +#define CFCR_PENAB 0x08 +#define CFCR_STOPB 0x04 +#define CFCR_8BITS 0x03 +#define CFCR_7BITS 0x02 +#define CFCR_6BITS 0x01 +#define CFCR_5BITS 0x00 + +/* modem control register */ +#define MCR_LOOPBACK 0x10 +#define MCR_IENABLE 0x08 +#define MCR_DRS 0x04 +#define MCR_RTS 0x02 +#define MCR_DTR 0x01 + +/* line status register */ +#define LSR_RCV_FIFO 0x80 +#define LSR_TSRE 0x40 +#define LSR_TXRDY 0x20 +#define LSR_BI 0x10 +#define LSR_FE 0x08 +#define LSR_PE 0x04 +#define LSR_OE 0x02 +#define LSR_RXRDY 0x01 +#define LSR_RCV_MASK 0x1f + +/* modem status register */ +#define MSR_DCD 0x80 +#define MSR_RI 0x40 +#define MSR_DSR 0x20 +#define MSR_CTS 0x10 +#define MSR_DDCD 0x08 +#define MSR_TERI 0x04 +#define MSR_DDSR 0x02 +#define MSR_DCTS 0x01 + +/* + * WARNING: Serial console is assumed to be at COM1 address + * and CONUNIT must be 0. + */ +#define CONADDR (0x3f8) +#define CONUNIT (0) diff --git a/sys/isa/timerreg.h b/sys/isa/timerreg.h new file mode 100644 index 000000000000..72c70227e3ed --- /dev/null +++ b/sys/isa/timerreg.h @@ -0,0 +1,89 @@ +/*- + * 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. + * + * $Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp $ + * + * 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. + */ + +/* + * 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/kern/subr_rlist.c b/sys/kern/subr_rlist.c new file mode 100644 index 000000000000..3adf5a819586 --- /dev/null +++ b/sys/kern/subr_rlist.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 1992 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 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. + * + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/kern/RCS/subr_rlist.c,v 1.2 92/01/21 21:29:31 william Exp $"; + +#include "sys/param.h" +#include "sys/cdefs.h" +#include "sys/malloc.h" +#include "rlist.h" + +/* + * Resource lists. + */ + +/* + * Add space to a resource list. Used to either + * initialize a list or return free space to it. + */ +rlist_free (rlp, start, end) +register struct rlist **rlp; unsigned start, end; { + struct rlist *head; + + head = *rlp; + +loop: + /* if nothing here, insert (tail of list) */ + if (*rlp == 0) { + *rlp = (struct rlist *)malloc(sizeof(**rlp), M_TEMP, M_NOWAIT); + (*rlp)->rl_start = start; + (*rlp)->rl_end = end; + (*rlp)->rl_next = 0; + return; + } + + /* if new region overlaps something currently present, panic */ + if (start >= (*rlp)->rl_start && start <= (*rlp)->rl_end) { + printf("Frag %d:%d, ent %d:%d ", start, end, + (*rlp)->rl_start, (*rlp)->rl_end); + panic("overlapping front rlist_free: freed twice?"); + } + if (end >= (*rlp)->rl_start && end <= (*rlp)->rl_end) { + printf("Frag %d:%d, ent %d:%d ", start, end, + (*rlp)->rl_start, (*rlp)->rl_end); + panic("overlapping tail rlist_free: freed twice?"); + } + + /* are we adjacent to this element? (in front) */ + if (end+1 == (*rlp)->rl_start) { + /* coalesce */ + (*rlp)->rl_start = start; + goto scan; + } + + /* are we before this element? */ + if (end < (*rlp)->rl_start) { + register struct rlist *nlp; + + nlp = (struct rlist *)malloc(sizeof(*nlp), M_TEMP, M_NOWAIT); + nlp->rl_start = start; + nlp->rl_end = end; + nlp->rl_next = *rlp; + *rlp = nlp; + return; + } + + /* are we adjacent to this element? (at tail) */ + if ((*rlp)->rl_end + 1 == start) { + /* coalesce */ + (*rlp)->rl_end = end; + goto scan; + } + + /* are we after this element */ + if (start > (*rlp)->rl_end) { + rlp = &((*rlp)->rl_next); + goto loop; + } else + panic("rlist_free: can't happen"); + +scan: + /* can we coalesce list now that we've filled a void? */ + { + register struct rlist *lp, *lpn; + + for (lp = head; lp->rl_next ;) { + lpn = lp->rl_next; + + /* coalesce ? */ + if (lp->rl_end + 1 == lpn->rl_start) { + lp->rl_end = lpn->rl_end; + lp->rl_next = lpn->rl_next; + free(lpn, M_TEMP); + } else + lp = lp->rl_next; + } + } +} + +/* + * Obtain a region of desired size from a resource list. + * If nothing available of that size, return 0. Otherwise, + * return a value of 1 and set resource start location with + * "*loc". (Note: loc can be zero if we don't wish the value) + */ +int rlist_alloc (rlp, size, loc) +struct rlist **rlp; unsigned size, *loc; { + register struct rlist *lp; + + + /* walk list, allocating first thing that's big enough (first fit) */ + for (; *rlp; rlp = &((*rlp)->rl_next)) + if(size <= (*rlp)->rl_end - (*rlp)->rl_start + 1) { + + /* hand it to the caller */ + if (loc) *loc = (*rlp)->rl_start; + (*rlp)->rl_start += size; + + /* did we eat this element entirely? */ + if ((*rlp)->rl_start > (*rlp)->rl_end) { + lp = (*rlp)->rl_next; + free (*rlp, M_TEMP); + *rlp = lp; + } + + return (1); + } + + /* nothing in list that's big enough */ + return (0); +} + +/* + * Finished with this resource list, reclaim all space and + * mark it as being empty. + */ +rlist_destroy (rlp) +struct rlist **rlp; { + struct rlist *lp, *nlp; + + lp = *rlp; + *rlp = 0; + for (; lp; lp = nlp) { + nlp = lp->rl_next; + free (lp, M_TEMP); + } +} diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c new file mode 100644 index 000000000000..57195f32cb91 --- /dev/null +++ b/sys/kern/subr_trap.c @@ -0,0 +1,547 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the University of Utah, and 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. + * + * @(#)trap.c 7.4 (Berkeley) 5/13/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00137 + * -------------------- ----- ---------------------- + * + * 08 Apr 93 Bruce Evans Several VM system fixes + * Paul Kranenburg Add counter for vmstat + */ +static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/trap.c,v 1.2 92/01/21 14:22:13 william Exp $"; + +/* + * 386 Trap and System call handleing + */ + +#include "machine/cpu.h" +#include "machine/psl.h" +#include "machine/reg.h" + +#include "param.h" +#include "systm.h" +#include "proc.h" +#include "user.h" +#include "acct.h" +#include "kernel.h" +#ifdef KTRACE +#include "ktrace.h" +#endif + +#include "vm/vm_param.h" +#include "vm/pmap.h" +#include "vm/vm_map.h" +#include "sys/vmmeter.h" + +#include "machine/trap.h" + + +struct sysent sysent[]; +int nsysent; +int dostacklimits; +unsigned rcr2(); +extern short cpl; + + +/* + * trap(frame): + * Exception, fault, and trap interface to BSD kernel. This + * common code is called from assembly language IDT gate entry + * routines that prepare a suitable stack frame, and restore this + * frame after the exception has been processed. Note that the + * effect is as if the arguments were passed call by reference. + */ + +/*ARGSUSED*/ +trap(frame) + struct trapframe frame; +{ + register int i; + register struct proc *p = curproc; + struct timeval syst; + int ucode, type, code, eva; + + frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */ + type = frame.tf_trapno; +#include "ddb.h" +#if NDDB > 0 + if (curpcb && curpcb->pcb_onfault) { + if (frame.tf_trapno == T_BPTFLT + || frame.tf_trapno == T_TRCTRAP) + if (kdb_trap (type, 0, &frame)) + return; + } +#endif + +/*pg("trap type %d code = %x eip = %x cs = %x eva = %x esp %x", + frame.tf_trapno, frame.tf_err, frame.tf_eip, + frame.tf_cs, rcr2(), frame.tf_esp);*/ +if(curpcb == 0 || curproc == 0) goto we_re_toast; + if (curpcb->pcb_onfault && frame.tf_trapno != 0xc) { +copyfault: + frame.tf_eip = (int)curpcb->pcb_onfault; + return; + } + + syst = p->p_stime; + if (ISPL(frame.tf_cs) == SEL_UPL) { + type |= T_USER; + p->p_regs = (int *)&frame; + curpcb->pcb_flags |= FM_TRAP; /* used by sendsig */ + } + + ucode=0; + eva = rcr2(); + code = frame.tf_err; + switch (type) { + + default: + we_re_toast: +#ifdef KDB + if (kdb_trap(&psl)) + return; +#endif +#if NDDB > 0 + if (kdb_trap (type, 0, &frame)) + return; +#endif + + printf("trap type %d code = %x eip = %x cs = %x eflags = %x ", + frame.tf_trapno, frame.tf_err, frame.tf_eip, + frame.tf_cs, frame.tf_eflags); + eva = rcr2(); + printf("cr2 %x cpl %x\n", eva, cpl); + /* type &= ~T_USER; */ /* XXX what the hell is this */ + panic("trap"); + /*NOTREACHED*/ + + case T_SEGNPFLT|T_USER: + case T_STKFLT|T_USER: + case T_PROTFLT|T_USER: /* protection fault */ + ucode = code + BUS_SEGM_FAULT ; + i = SIGBUS; + break; + + case T_PRIVINFLT|T_USER: /* privileged instruction fault */ + case T_RESADFLT|T_USER: /* reserved addressing fault */ + case T_RESOPFLT|T_USER: /* reserved operand fault */ + case T_FPOPFLT|T_USER: /* coprocessor operand fault */ + ucode = type &~ T_USER; + i = SIGILL; + break; + + case T_ASTFLT|T_USER: /* Allow process switch */ + astoff(); + cnt.v_soft++; + if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) { + addupc(frame.tf_eip, &p->p_stats->p_prof, 1); + p->p_flag &= ~SOWEUPC; + } + goto out; + + case T_DNA|T_USER: +#ifdef NPX + /* if a transparent fault (due to context switch "late") */ + if (npxdna()) return; +#endif + i = math_emulate(&frame); + if (i == 0) return; + ucode = FPE_FPU_NP_TRAP; + break; + + case T_BOUND|T_USER: + ucode = FPE_SUBRNG_TRAP; + i = SIGFPE; + break; + + case T_OFLOW|T_USER: + ucode = FPE_INTOVF_TRAP; + i = SIGFPE; + break; + + case T_DIVIDE|T_USER: + ucode = FPE_INTDIV_TRAP; + i = SIGFPE; + break; + + case T_ARITHTRAP|T_USER: + ucode = code; + i = SIGFPE; + break; + + case T_PAGEFLT: /* allow page faults in kernel mode */ +#if 0 + /* XXX - check only applies to 386's and 486's with WP off */ + if (code & PGEX_P) goto we_re_toast; +#endif + + /* fall into */ + case T_PAGEFLT|T_USER: /* page fault */ + { + register vm_offset_t va; + register struct vmspace *vm = p->p_vmspace; + register vm_map_t map; + int rv; + vm_prot_t ftype; + extern vm_map_t kernel_map; + unsigned nss,v; + + va = trunc_page((vm_offset_t)eva); + /* + * Avoid even looking at pde_v(va) for high va's. va's + * above VM_MAX_KERNEL_ADDRESS don't correspond to normal + * PDE's (half of them correspond to APDEpde and half to + * an unmapped kernel PDE). va's betweeen 0xFEC00000 and + * VM_MAX_KERNEL_ADDRESS correspond to unmapped kernel PDE's + * (XXX - why are only 3 initialized when 6 are required to + * reach VM_MAX_KERNEL_ADDRESS?). Faulting in an unmapped + * kernel page table would give inconsistent PTD's. + * + * XXX - faulting in unmapped page tables wastes a page if + * va turns out to be invalid. + * + * XXX - should "kernel address space" cover the kernel page + * tables? Might have same problem with PDEpde as with + * APDEpde (or there may be no problem with APDEpde). + */ + if (va > 0xFEBFF000) { + rv = KERN_FAILURE; /* becomes SIGBUS */ + goto nogo; + } + /* + * It is only a kernel address space fault iff: + * 1. (type & T_USER) == 0 and + * 2. pcb_onfault not set or + * 3. pcb_onfault set but supervisor space fault + * The last can occur during an exec() copyin where the + * argument space is lazy-allocated. + */ + if (type == T_PAGEFLT && va >= KERNBASE) + map = kernel_map; + else + map = &vm->vm_map; + if (code & PGEX_W) + ftype = VM_PROT_READ | VM_PROT_WRITE; + else + ftype = VM_PROT_READ; + +#ifdef DEBUG + if (map == kernel_map && va == 0) { + printf("trap: bad kernel access at %x\n", va); + goto we_re_toast; + } +#endif + + /* + * XXX: rude hack to make stack limits "work" + */ + nss = 0; + if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map + && dostacklimits) { + nss = clrnd(btoc((unsigned)vm->vm_maxsaddr + + MAXSSIZ - (unsigned)va)); + if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) { +/*pg("trap rlimit %d, maxsaddr %x va %x ", nss, vm->vm_maxsaddr, va);*/ + rv = KERN_FAILURE; + goto nogo; + } + } + + /* check if page table is mapped, if not, fault it first */ +#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v) + if (!pde_v(va)) { + v = trunc_page(vtopte(va)); + rv = vm_fault(map, v, ftype, FALSE); + if (rv != KERN_SUCCESS) goto nogo; + /* check if page table fault, increment wiring */ + vm_map_pageable(map, v, round_page(v+1), FALSE); + } else v=0; + rv = vm_fault(map, va, ftype, FALSE); + if (rv == KERN_SUCCESS) { + /* + * XXX: continuation of rude stack hack + */ + if (nss > vm->vm_ssize) + vm->vm_ssize = nss; + va = trunc_page(vtopte(va)); + /* for page table, increment wiring + as long as not a page table fault as well */ + if (!v && type != T_PAGEFLT) + vm_map_pageable(map, va, round_page(va+1), FALSE); + if (type == T_PAGEFLT) + return; + goto out; + } +nogo: + if (type == T_PAGEFLT) { + if (curpcb->pcb_onfault) + goto copyfault; + printf("vm_fault(%x, %x, %x, 0) -> %x\n", + map, va, ftype, rv); + printf(" type %x, code %x\n", + type, code); + goto we_re_toast; + } + i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; + break; + } + +#if NDDB == 0 + case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */ + frame.tf_eflags &= ~PSL_T; + + /* Q: how do we turn it on again? */ + return; +#endif + + case T_BPTFLT|T_USER: /* bpt instruction fault */ + case T_TRCTRAP|T_USER: /* trace trap */ + frame.tf_eflags &= ~PSL_T; + i = SIGTRAP; + break; + +#include "isa.h" +#if NISA > 0 + case T_NMI: + case T_NMI|T_USER: +#if NDDB > 0 + /* NMI can be hooked up to a pushbutton for debugging */ + printf ("NMI ... going to debugger\n"); + if (kdb_trap (type, 0, &frame)) + return; +#endif + /* machine/parity/power fail/"kitchen sink" faults */ + if(isa_nmi(code) == 0) return; + else goto we_re_toast; +#endif + } + + trapsignal(p, i, ucode); + if ((type & T_USER) == 0) + return; +out: + while (i = CURSIG(p)) + psig(i); + p->p_pri = p->p_usrpri; + if (want_resched) { + /* + * 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 setrq ourselves but before we + * swtch()'ed, we might not be on the queue indicated by + * our priority. + */ + (void) splclock(); + setrq(p); + p->p_stats->p_ru.ru_nivcsw++; + swtch(); + (void) splnone(); + while (i = CURSIG(p)) + psig(i); + } + if (p->p_stats->p_prof.pr_scale) { + int ticks; + struct timeval *tv = &p->p_stime; + + ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + + (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); + if (ticks) { +#ifdef PROFTIMER + extern int profscale; + addupc(frame.tf_eip, &p->p_stats->p_prof, + ticks * profscale); +#else + addupc(frame.tf_eip, &p->p_stats->p_prof, ticks); +#endif + } + } + curpri = p->p_pri; + curpcb->pcb_flags &= ~FM_TRAP; /* used by sendsig */ +} + +/* + * Compensate for 386 brain damage (missing URKR) + */ +int trapwrite(unsigned addr) { + int rv; + vm_offset_t va; + + va = trunc_page((vm_offset_t)addr); + if (va > VM_MAXUSER_ADDRESS) return(1); + rv = vm_fault(&curproc->p_vmspace->vm_map, va, + VM_PROT_READ | VM_PROT_WRITE, FALSE); + if (rv == KERN_SUCCESS) return(0); + else return(1); +} + +/* + * syscall(frame): + * System call request from POSIX system call gate interface to kernel. + * Like trap(), argument is call by reference. + */ +/*ARGSUSED*/ +syscall(frame) + volatile struct syscframe frame; +{ + register int *locr0 = ((int *)&frame); + register caddr_t params; + register int i; + register struct sysent *callp; + register struct proc *p = curproc; + struct timeval syst; + int error, opc; + int args[8], rval[2]; + int code; + +#ifdef lint + r0 = 0; r0 = r0; r1 = 0; r1 = r1; +#endif + syst = p->p_stime; + if (ISPL(frame.sf_cs) != SEL_UPL) + panic("syscall"); + + code = frame.sf_eax; + curpcb->pcb_flags &= ~FM_TRAP; /* used by sendsig */ + p->p_regs = (int *)&frame; + params = (caddr_t)frame.sf_esp + sizeof (int) ; + + /* + * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always. + */ + opc = frame.sf_eip - 7; + callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; + if (callp == sysent) { + i = fuword(params); + params += sizeof (int); + callp = (code >= nsysent) ? &sysent[63] : &sysent[code]; + } + + if ((i = callp->sy_narg * sizeof (int)) && + (error = copyin(params, (caddr_t)args, (u_int)i))) { + frame.sf_eax = error; + frame.sf_eflags |= PSL_C; /* carry bit */ +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, callp->sy_narg, &args); +#endif + goto done; + } +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, callp->sy_narg, &args); +#endif + rval[0] = 0; + rval[1] = frame.sf_edx; +/*pg("%d. s %d\n", p->p_pid, code);*/ + error = (*callp->sy_call)(p, args, rval); + if (error == ERESTART) + frame.sf_eip = opc; + else if (error != EJUSTRETURN) { + if (error) { +/*pg("error %d", error);*/ + frame.sf_eax = error; + frame.sf_eflags |= PSL_C; /* carry bit */ + } else { + frame.sf_eax = rval[0]; + frame.sf_edx = rval[1]; + frame.sf_eflags &= ~PSL_C; /* carry bit */ + } + } + /* else if (error == EJUSTRETURN) */ + /* nothing to do */ +done: + /* + * Reinitialize proc pointer `p' as it may be different + * if this is a child returning from fork syscall. + */ + p = curproc; + while (i = CURSIG(p)) + psig(i); + p->p_pri = p->p_usrpri; + if (want_resched) { + /* + * 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 setrq ourselves but before we + * swtch()'ed, we might not be on the queue indicated by + * our priority. + */ + (void) splclock(); + setrq(p); + p->p_stats->p_ru.ru_nivcsw++; + swtch(); + (void) splnone(); + while (i = CURSIG(p)) + psig(i); + } + if (p->p_stats->p_prof.pr_scale) { + int ticks; + struct timeval *tv = &p->p_stime; + + ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + + (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); + if (ticks) { +#ifdef PROFTIMER + extern int profscale; + addupc(frame.sf_eip, &p->p_stats->p_prof, + ticks * profscale); +#else + addupc(frame.sf_eip, &p->p_stats->p_prof, ticks); +#endif + } + } + curpri = p->p_pri; +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(p->p_tracep, code, error, rval[0]); +#endif +#ifdef DIAGNOSTICx +{ extern int _udatasel, _ucodesel; + if (frame.sf_ss != _udatasel) + printf("ss %x call %d\n", frame.sf_ss, code); + if ((frame.sf_cs&0xffff) != _ucodesel) + printf("cs %x call %d\n", frame.sf_cs, code); + if (frame.sf_eip > VM_MAXUSER_ADDRESS) { + printf("eip %x call %d\n", frame.sf_eip, code); + frame.sf_eip = 0; + } +} +#endif +} diff --git a/sys/kern/tty_cons.c b/sys/kern/tty_cons.c new file mode 100644 index 000000000000..6189d721115f --- /dev/null +++ b/sys/kern/tty_cons.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1991 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. + * + * 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. + * + * @(#)cons.c 7.2 (Berkeley) 5/9/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00083 + * -------------------- ----- ---------------------- + * + * 16 Aug 92 Pace Willisson /dev/console redirect (xterm -C, etc.) + * 14 Mar 93 Chris G. Demetriou Moved pg() here from isa/pccons.c + */ + + +#include "sys/param.h" +#include "sys/proc.h" +#include "sys/user.h" +#include "sys/systm.h" +#include "sys/buf.h" +#include "sys/ioctl.h" +#include "sys/tty.h" +#include "sys/file.h" +#include "sys/conf.h" + +#include "cons.h" + +/* XXX - all this could be autoconfig()ed */ +int pccnprobe(), pccninit(), pccngetc(), pccnputc(); +#include "com.h" +#if NCOM > 0 +int comcnprobe(), comcninit(), comcngetc(), comcnputc(); +#endif + +struct consdev constab[] = { + { pccnprobe, pccninit, pccngetc, pccnputc }, +#if NCOM > 0 + { comcnprobe, comcninit, comcngetc, comcnputc }, +#endif + { 0 }, +}; +/* end XXX */ + +struct tty *constty = 0; /* virtual console output device */ +struct consdev *cn_tab; /* physical console device info */ +struct tty *cn_tty; /* XXX: console tty struct for tprintf */ + +cninit() +{ + register struct consdev *cp; + + /* + * Collect information about all possible consoles + * and find the one with highest priority + */ + for (cp = constab; cp->cn_probe; cp++) { + (*cp->cn_probe)(cp); + if (cp->cn_pri > CN_DEAD && + (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri)) + cn_tab = cp; + } + /* + * No console, we can handle it + */ + if ((cp = cn_tab) == NULL) + return; + /* + * Turn on console + */ + cn_tty = cp->cn_tp; + (*cp->cn_init)(cp); +} + +cnopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + if (cn_tab == NULL) + return (0); + dev = cn_tab->cn_dev; + return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p)); +} + +cnclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + if (cn_tab == NULL) + return (0); + dev = cn_tab->cn_dev; + return ((*cdevsw[major(dev)].d_close)(dev, flag, mode, p)); +} + +cnread(dev, uio, flag) + dev_t dev; + struct uio *uio; +{ + if (cn_tab == NULL) + return (0); + dev = cn_tab->cn_dev; + return ((*cdevsw[major(dev)].d_read)(dev, uio, flag)); +} + +cnwrite(dev, uio, flag) + dev_t dev; + struct uio *uio; +{ + if (cn_tab == NULL) + return (0); + if (constty) /* 16 Aug 92*/ + dev = constty->t_dev; + else + dev = cn_tab->cn_dev; + return ((*cdevsw[major(dev)].d_write)(dev, uio, flag)); +} + +cnioctl(dev, cmd, data, flag, p) + dev_t dev; + caddr_t data; + struct proc *p; +{ + int error; + + if (cn_tab == NULL) + return (0); + /* + * Superuser can always use this to wrest control of console + * output from the "virtual" console. + */ + if (cmd == TIOCCONS && constty) { + error = suser(p->p_ucred, (u_short *) NULL); + if (error) + return (error); + constty = NULL; + return (0); + } + dev = cn_tab->cn_dev; + return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p)); +} + +/*ARGSUSED*/ +cnselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; +{ + if (cn_tab == NULL) + return (1); + return (ttselect(cn_tab->cn_dev, rw, p)); +} + +cngetc() +{ + if (cn_tab == NULL) + return (0); + return ((*cn_tab->cn_getc)(cn_tab->cn_dev)); +} + +cnputc(c) + register int c; +{ + if (cn_tab == NULL) + return; + if (c) { + (*cn_tab->cn_putc)(cn_tab->cn_dev, c); + if (c == '\n') + (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); + } +} + +pg(p,q,r,s,t,u,v,w,x,y,z) char *p; { + printf(p,q,r,s,t,u,v,w,x,y,z); + printf("\n>"); + return(cngetc()); +} + + diff --git a/sys/powerpc/include/_limits.h b/sys/powerpc/include/_limits.h new file mode 100644 index 000000000000..73474608f7cf --- /dev/null +++ b/sys/powerpc/include/_limits.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1988 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 7.2 (Berkeley) 6/28/90 + */ + +#define CHAR_BIT 8 /* number of bits in a char */ +#define CLK_TCK 60 /* ticks per second */ +#define MB_LEN_MAX 1 /* no multibyte characters */ + +#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */ +#define SCHAR_MAX 0x7f /* min value for a signed char */ + +#define UCHAR_MAX 0xff /* max value for an unsigned char */ +#define CHAR_MAX 0x7f /* max value for a char */ +#define CHAR_MIN (-0x7f-1) /* min value for a char */ + +#define USHRT_MAX 0xffff /* max value for an unsigned short */ +#define SHRT_MAX 0x7fff /* max value for a short */ +#define SHRT_MIN (-0x7fff-1) /* min value for a short */ + +#define UINT_MAX 0xffffffff /* max value for an unsigned int */ +#define INT_MAX 0x7fffffff /* max value for an int */ +#define INT_MIN (-0x7fffffff-1) /* min value for an int */ + +#define ULONG_MAX 0xffffffff /* max value for an unsigned long */ +#define LONG_MAX 0x7fffffff /* max value for a long */ +#define LONG_MIN (-0x7fffffff-1) /* min value for a long */ diff --git a/sys/powerpc/include/limits.h b/sys/powerpc/include/limits.h new file mode 100644 index 000000000000..73474608f7cf --- /dev/null +++ b/sys/powerpc/include/limits.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1988 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 7.2 (Berkeley) 6/28/90 + */ + +#define CHAR_BIT 8 /* number of bits in a char */ +#define CLK_TCK 60 /* ticks per second */ +#define MB_LEN_MAX 1 /* no multibyte characters */ + +#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */ +#define SCHAR_MAX 0x7f /* min value for a signed char */ + +#define UCHAR_MAX 0xff /* max value for an unsigned char */ +#define CHAR_MAX 0x7f /* max value for a char */ +#define CHAR_MIN (-0x7f-1) /* min value for a char */ + +#define USHRT_MAX 0xffff /* max value for an unsigned short */ +#define SHRT_MAX 0x7fff /* max value for a short */ +#define SHRT_MIN (-0x7fff-1) /* min value for a short */ + +#define UINT_MAX 0xffffffff /* max value for an unsigned int */ +#define INT_MAX 0x7fffffff /* max value for an int */ +#define INT_MIN (-0x7fffffff-1) /* min value for an int */ + +#define ULONG_MAX 0xffffffff /* max value for an unsigned long */ +#define LONG_MAX 0x7fffffff /* max value for a long */ +#define LONG_MIN (-0x7fffffff-1) /* min value for a long */ diff --git a/sys/scsi/README b/sys/scsi/README new file mode 100644 index 000000000000..16e0998eb292 --- /dev/null +++ b/sys/scsi/README @@ -0,0 +1,182 @@ + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system +This release consists of the following files +(relative to the base of the kernel tree) + + +MAKEDEV + +scsi +scsi/README +scsi/scsiconf.h +scsi/scsiconf.c +scsi/scsi_all.h + +scsi/scsi_disk.h +scsi/sd.c + +scsi/scsi_tape.h +scsi/st.c + +sys/chio.h +scsi/scsi_changer.h +scsi/ch.c + +sys/cdio.h +scsi/scsi_cd.h +scsi/cd.c + +i386/conf/SCSITEST +i386/isa/aha1542.c + +README.AHA1742 +i386/conf/AHBTEST +i386/isa/aha1742.c + +i386/conf/UHATEST +i386/isa/ultra14f.c + +i386/conf/BTTEST +i386/isa/bt742a.c + + + +---------------------------------------------------------------- +This scsi system is designed to allow the re-use of top end drivers +such as disk and tape drivers, with different scsi adapters. + +As of writing this document, There are top end drivers working for: +---------------------------------------------------------------- +generic scsi disk +generic scsi tape +cd-rom (plays music under the xcplayer (?) program) +AEG Character recognition devices * +Calera Character recognition devices * +Kodak IL900 scanner * +Exabyte tape changer device. +---------------------------------------------------------------- + + +There are also working bottom end drivers for: +---------------------------------------------------------------- +adaptec 1542 (and 1742 in 1542 mode) +bustec 742a +adaptec 174x +Ultrastore 14f +---------------------------------------------------------------- + + +Work is proceeding on the following bottom end drivers: +---------------------------------------------------------------- +Future Domain (1680)** hosler@tfs.com & me +Future Domain (8 bit)**** rpr@oce.nl +WD7000** terry@icarus.weber.edu +seagate st01/st02**** overby@aspen.cray.com ? +---------------------------------------------------------------- +* drivers not made public (proprietary.. proof that the concept works though) +** driver not yet released but working. +*** just a dream so far. +**** some amount more than just a dream so far. + + +################## Using the scsi system ################## +------------minor numbers--------------- +This scsi system does not allocate minor numbers to devices depending +on their SCSI IDs is any way. A devices minor number is dependant +on the order in which it was found. +e.g. the first tape found will become st0 (minor number 0) + the second found will become st1 (minor number 16) + the third will become st2 (minor 32) + etc. + +These devices could be on the same scsi bus or different scsi busses. +That would not change their minor numbers. + +It is possible to run two different TYPES of scsi adapters at the +same time and have st0 on one and st1 on another. (for example) + +There is a scheme supported in which scsi devices can be 'wired in' even +if they are not present or powered on at probe time. (see scsiconf.c) + +--------------getting started------------ +It should be possible to use the /dev entries for as0 as if they were +/dev entries for sd0 and the old as bootblocks should +continue to work if you are using an adaptec 1542b. + +--------------making devices------------ +A changed version of /dev/MAKEDEV is supplied that +can be used to make devices sd[01234] and st[01234] + +e.g. +cd /dev +sh MAKEDEV sd0 sd1 sd2 st0 st1 cd0 + + +The tape devices are as follows: +rst0 basic raw device, will rewind on close +nrst0 will not rewind on close +erst0 will rewind and EJECTon close +nerst0 will not rewind and WILL eject (some devices may rewind anyhow) + +------------future enhancements-------------- +Some people have indicated that they would like to have the SCSI ID +encoded into the minor number in some way, and +this may be supported at some timein the future, using +minor numbers greater than 128. (or maybe a different major number) + +I will also be writing (probably) a generic scsi-error +handling routine that will be table driven, so that the routine can +be removed from each individual driver. With enough care, +two similar devices with different error codes (quite common) could run +the same driver but use different error tables. + +--------------file layout------------------- +Originally I had all scsi definitions in one file: scsi.h +I have since moved definitions of commands so that all +definitions needed for a particular type of device are +found together in the include file of that name. +This approximatly follows the layout of their definition +in the SCSI-2 spec. +As such they are: + +scsi_all.h general commands for all devices --- CHAPTER 7 +scsi-disk.h commands relevant to disk --- CHAPTER 8 +scsi-tape.h commands for scsi tapes --- CHAPTER 9 +scsi-cd.h commands for cd-roms (and audio) --- CHAPTER 13 +scsi-changer.h commands medium changer devices --- CHAPTER 16 + +---------ioctl definitions------------- +User accessable structures (e.g. ioctl definitions) have been +placed in sys/cdio and sys/chio (based after sys/mtio for +the ioctls for mag tapes (including st). + +-----------cd-rom----------------- +The cd rom driver ha been tested by a number of people and +grefen@wilbur.zdv.uni-mainz.de has completed the audio play +functions. +He tells me he has some Public Domain package that +allows an control of the cd player from an Xwindow +but I don't have it. + +-------------media changer--------------- +Once again courtesy of grefen@wilbur.zdv.uni-mainz.de. +I have not tested this but he assures me it's ready for testing. +If anyone has an exabyte tape changer or similar, +contact the author for information regarding the control interface +and program. + +-----------booting from an AHA-174x--------- +For some reason I have not yet worked out, +the BIOS-based bootblocks I have posted will not boot +from the aha1742 in extended mode. (it can't be serious +because the MACH version works) This is in fact not a +problem because the aha1742 driver will force the board into extended +mode during probe, so it can be left in standard mode during the boot. +During the next reboot, the bios will place it back in standard mode +ready for the NEXT boot. + diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c new file mode 100644 index 000000000000..2a2261e697bb --- /dev/null +++ b/sys/scsi/cd.c @@ -0,0 +1,1722 @@ +/* + * Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + */ +static char rev[] = "$Revision: 1.3 $"; + +/* + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 2 00149 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * 20 Apr 93 Julian Elishcer Fixed error reporting + */ + +#define SPLCD splbio +#define ESUCCESS 0 +#include <cd.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/dkbad.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/buf.h> +#include <sys/uio.h> +#include <sys/malloc.h> +#include <sys/cdio.h> + +#include <sys/errno.h> +#include <sys/disklabel.h> +#include <scsi/scsi_all.h> +#include <scsi/scsi_cd.h> +#include <scsi/scsi_disk.h> /* rw_big and start_stop come from there */ +#include <scsi/scsiconf.h> + +long int cdstrats,cdqueues; + + +#include <ddb.h> +#if NDDB > 0 +int Debugger(); +#else NDDB > 0 +#define Debugger() +#endif NDDB > 0 + + +#define PAGESIZ 4096 +#define SECSIZE 2048 /* XXX */ /* default only */ +#define CDOUTSTANDING 2 +#define CDQSIZE 4 +#define CD_RETRIES 4 + +#define UNITSHIFT 3 +#define PARTITION(z) (minor(z) & 0x07) +#define RAW_PART 3 +#define UNIT(z) ( (minor(z) >> UNITSHIFT) ) + + +extern int hz; +int cd_done(); +int cdstrategy(); +int cd_debug = 0; + +struct buf cd_buf_queue[NCD]; +struct scsi_xfer cd_scsi_xfer[NCD][CDOUTSTANDING]; /* XXX */ +struct scsi_xfer *cd_free_xfer[NCD]; +int cd_xfer_block_wait[NCD]; + +struct cd_data +{ + int flags; +#define CDVALID 0x02 /* PARAMS LOADED */ +#define CDINIT 0x04 /* device has been init'd */ +#define CDWAIT 0x08 /* device has someone waiting */ +#define CDHAVELABEL 0x10 /* have read the label */ + struct scsi_switch *sc_sw; /* address of scsi low level switch */ + int ctlr; /* so they know which one we want */ + int targ; /* our scsi target ID */ + int lu; /* out scsi lu */ + int cmdscount; /* cmds allowed outstanding by board*/ + struct cd_parms + { + int blksize; + u_long disksize; /* total number sectors */ + }params; + struct disklabel disklabel; + int partflags[MAXPARTITIONS]; /* per partition flags */ +#define CDOPEN 0x01 + int openparts; /* one bit for each open partition */ +}cd_data[NCD]; + +#define CD_STOP 0 +#define CD_START 1 +#define CD_EJECT -2 + + +static int next_cd_unit = 0; +/***********************************************************************\ +* The routine called by the low level scsi routine when it discovers * +* A device suitable for this driver * +\***********************************************************************/ +int cdattach(ctlr,targ,lu,scsi_switch) +struct scsi_switch *scsi_switch; +{ + int unit,i; + unsigned char *tbl; + struct cd_data *cd; + struct cd_parms *dp; + + unit = next_cd_unit++; + cd = cd_data + unit; + dp = &(cd->params); + if(scsi_debug & PRINTROUTINES) printf("cdattach: "); + /*******************************************************\ + * Check we have the resources for another drive * + \*******************************************************/ + if( unit >= NCD) + { + printf("Too many scsi CDs..(%d > %d) reconfigure kernel",(unit + 1),NCD); + return(0); + } + /*******************************************************\ + * Store information needed to contact our base driver * + \*******************************************************/ + cd->sc_sw = scsi_switch; + cd->ctlr = ctlr; + cd->targ = targ; + cd->lu = lu; + cd->cmdscount = CDOUTSTANDING; /* XXX (ask the board) */ + + + i = cd->cmdscount; + while(i-- ) + { + cd_scsi_xfer[unit][i].next = cd_free_xfer[unit]; + cd_free_xfer[unit] = &cd_scsi_xfer[unit][i]; + } + /*******************************************************\ + * Use the subdriver to request information regarding * + * the drive. We cannot use interrupts yet, so the * + * request must specify this. * + \*******************************************************/ + cd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK); + if(dp->disksize) + { + printf("cd present\n"); + } + else + { + printf("drive empty\n"); + } + cd->flags |= CDINIT; + return; + +} + + + +/*******************************************************\ +* open the device. Make sure the partition info * +* is a up-to-date as can be. * +\*******************************************************/ +cdopen(dev) +{ + int errcode = 0; + int unit, part; + struct cd_parms cd_parms; + struct cd_data *cd ; + + unit = UNIT(dev); + part = PARTITION(dev); + cd = cd_data + unit; + if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) + printf("cdopen: dev=0x%x (unit %d (of %d),partition %d)\n" + , dev, unit, NCD, part); + /*******************************************************\ + * Check the unit is legal * + \*******************************************************/ + if ( unit >= NCD ) + { + return(ENXIO); + } + /*******************************************************\ + * Make sure the disk has been initialised * + * At some point in the future, get the scsi driver * + * to look for a new device if we are not initted * + \*******************************************************/ + if (! (cd->flags & CDINIT)) + return(ENXIO); + + /*******************************************************\ + * If it's been invalidated, and not everybody has * + * closed it then forbid re-entry. * + * (may have changed media) * + \*******************************************************/ + if ((! (cd->flags & CDVALID)) + && ( cd->openparts)) + return(ENXIO); + /*******************************************************\ + * Check that it is still responding and ok. * + * if the media has been changed this will result in a * + * "unit attention" error which the error code will * + * disregard because the CDVALID flag is not yet set * + \*******************************************************/ + if (cd_req_sense(unit, SCSI_SILENT) != 0) { + if(scsi_debug & TRACEOPENS) + printf("not reponding\n"); + return(ENXIO); + } + if(scsi_debug & TRACEOPENS) + printf("Device present\n"); + /*******************************************************\ + * In case it is a funny one, tell it to start * + * not needed for hard drives * + \*******************************************************/ + cd_start_unit(unit,part,CD_START); + cd_prevent_unit(unit,PR_PREVENT,SCSI_SILENT); + if(scsi_debug & TRACEOPENS) + printf("started "); + /*******************************************************\ + * Load the physical device parameters * + \*******************************************************/ + cd_get_parms(unit, 0); + if(scsi_debug & TRACEOPENS) + printf("Params loaded "); + /*******************************************************\ + * Load the partition info if not already loaded * + \*******************************************************/ + cdgetdisklabel(unit); + if(scsi_debug & TRACEOPENS) + printf("Disklabel fabricated "); + /*******************************************************\ + * Check the partition is legal * + \*******************************************************/ + if (( part >= cd->disklabel.d_npartitions ) + && (part != RAW_PART)) + { + if(scsi_debug & TRACEOPENS) + printf("partition %d > %d\n",part + ,cd->disklabel.d_npartitions); + cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT); + return(ENXIO); + } + /*******************************************************\ + * Check that the partition exists * + \*******************************************************/ + if (( cd->disklabel.d_partitions[part].p_fstype != FS_UNUSED ) + || (part == RAW_PART)) + { + cd->partflags[part] |= CDOPEN; + cd->openparts |= (1 << part); + if(scsi_debug & TRACEOPENS) + printf("open complete\n"); + cd->flags |= CDVALID; + } + else + { + if(scsi_debug & TRACEOPENS) + printf("part %d type UNUSED\n",part); + cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT); + return(ENXIO); + } + return(0); +} + +/*******************************************************\ +* Get ownership of a scsi_xfer structure * +* If need be, sleep on it, until it comes free * +\*******************************************************/ +struct scsi_xfer *cd_get_xs(unit,flags) +int flags; +int unit; +{ + struct scsi_xfer *xs; + int s; + + if(flags & (SCSI_NOSLEEP | SCSI_NOMASK)) + { + if (xs = cd_free_xfer[unit]) + { + cd_free_xfer[unit] = xs->next; + xs->flags = 0; + } + } + else + { + s = SPLCD(); + while (!(xs = cd_free_xfer[unit])) + { + cd_xfer_block_wait[unit]++; /* someone waiting! */ + sleep((caddr_t)&cd_free_xfer[unit], PRIBIO+1); + cd_xfer_block_wait[unit]--; + } + cd_free_xfer[unit] = xs->next; + splx(s); + xs->flags = 0; + } + return(xs); +} + +/*******************************************************\ +* Free a scsi_xfer, wake processes waiting for it * +\*******************************************************/ +cd_free_xs(unit,xs,flags) +struct scsi_xfer *xs; +int unit; +int flags; +{ + int s; + + if(flags & SCSI_NOMASK) + { + if (cd_xfer_block_wait[unit]) + { + printf("doing a wakeup from NOMASK mode\n"); + wakeup((caddr_t)&cd_free_xfer[unit]); + } + xs->next = cd_free_xfer[unit]; + cd_free_xfer[unit] = xs; + } + else + { + s = SPLCD(); + if (cd_xfer_block_wait[unit]) + wakeup((caddr_t)&cd_free_xfer[unit]); + xs->next = cd_free_xfer[unit]; + cd_free_xfer[unit] = xs; + splx(s); + } +} + +/*******************************************************\ +* trim the size of the transfer if needed, * +* called by physio * +* basically the smaller of our max and the scsi driver's* +* minphys (note we have no max ourselves) * +\*******************************************************/ +/* Trim buffer length if buffer-size is bigger than page size */ +void cdminphys(bp) +struct buf *bp; +{ + (*(cd_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp); +} + +/*******************************************************\ +* Actually translate the requested transfer into * +* one the physical driver can understand * +* The transfer is described by a buf and will include * +* only one physical transfer. * +\*******************************************************/ + +int cdstrategy(bp) +struct buf *bp; +{ + struct buf *dp; + unsigned int opri; + struct cd_data *cd ; + int unit; + + cdstrats++; + unit = UNIT((bp->b_dev)); + cd = cd_data + unit; + if(scsi_debug & PRINTROUTINES) printf("\ncdstrategy "); + if(scsi_debug & SHOWREQUESTS) printf("cd%d: %d bytes @ blk%d\n", + unit,bp->b_bcount,bp->b_blkno); + cdminphys(bp); + /*******************************************************\ + * If the device has been made invalid, error out * + * maybe the media changed * + \*******************************************************/ + if(!(cd->flags & CDVALID)) + { + bp->b_error = EIO; + goto bad; + } + /*******************************************************\ + * can't ever write to a CD * + \*******************************************************/ + if ((bp->b_flags & B_READ) == 0) { + bp->b_error = EROFS; + goto bad; + } + /*******************************************************\ + * If it's a null transfer, return immediatly * + \*******************************************************/ + if (bp->b_bcount == 0) { + goto done; + } + + /*******************************************************\ + * Decide which unit and partition we are talking about * + \*******************************************************/ + if(PARTITION(bp->b_dev) != RAW_PART) + { + if (!(cd->flags & CDHAVELABEL)) + { + bp->b_error = EIO; + goto bad; + } + /* + * do bounds checking, adjust transfer. if error, process. + * if end of partition, just return + */ + if (bounds_check_with_label(bp,&cd->disklabel,1) <= 0) + goto done; + /* otherwise, process transfer request */ + } + + opri = SPLCD(); + dp = &cd_buf_queue[unit]; + + /*******************************************************\ + * Place it in the queue of disk activities for this disk* + \*******************************************************/ + disksort(dp, bp); + + /*******************************************************\ + * Tell the device to get going on the transfer if it's * + * not doing anything, otherwise just wait for completion* + \*******************************************************/ + cdstart(unit); + + splx(opri); + return; +bad: + bp->b_flags |= B_ERROR; +done: + + /*******************************************************\ + * Correctly set the buf to indicate a completed xfer * + \*******************************************************/ + bp->b_resid = bp->b_bcount; + biodone(bp); + return; +} + +/***************************************************************\ +* cdstart looks to see if there is a buf waiting for the device * +* and that the device is not already busy. If both are true, * +* It deques the buf and creates a scsi command to perform the * +* transfer in the buf. The transfer request will call cd_done * +* on completion, which will in turn call this routine again * +* so that the next queued transfer is performed. * +* The bufs are queued by the strategy routine (cdstrategy) * +* * +* This routine is also called after other non-queued requests * +* have been made of the scsi driver, to ensure that the queue * +* continues to be drained. * +* * +* must be called at the correct (highish) spl level * +\***************************************************************/ +/* cdstart() is called at SPLCD from cdstrategy and cd_done*/ +cdstart(unit) +int unit; +{ + register struct buf *bp = 0; + register struct buf *dp; + struct scsi_xfer *xs; + struct scsi_rw_big cmd; + int blkno, nblk; + struct cd_data *cd = cd_data + unit; + struct partition *p ; + + if(scsi_debug & PRINTROUTINES) printf("cdstart%d ",unit); + /*******************************************************\ + * See if there is a buf to do and we are not already * + * doing one * + \*******************************************************/ + if(!cd_free_xfer[unit]) + { + return; /* none for us, unit already underway */ + } + + if(cd_xfer_block_wait[unit]) /* there is one, but a special waits */ + { + return; /* give the special that's waiting a chance to run */ + } + + + dp = &cd_buf_queue[unit]; + if ((bp = dp->b_actf) != NULL) /* yes, an assign */ + { + dp->b_actf = bp->av_forw; + } + else + { + return; + } + + xs=cd_get_xs(unit,0); /* ok we can grab it */ + xs->flags = INUSE; /* Now ours */ + /***************************************************************\ + * Should reject all queued entries if CDVALID is not true * + \***************************************************************/ + if(!(cd->flags & CDVALID)) + { + goto bad; /* no I/O.. media changed or something */ + } + + /*******************************************************\ + * We have a buf, now we should move the data into * + * a scsi_xfer definition and try start it * + \*******************************************************/ + /*******************************************************\ + * First, translate the block to absolute * + * and put it in terms of the logical blocksize of the * + * device.. * + \*******************************************************/ + p = cd->disklabel.d_partitions + PARTITION(bp->b_dev); + blkno = ((bp->b_blkno / (cd->params.blksize/512)) + p->p_offset); + nblk = (bp->b_bcount + (cd->params.blksize - 1)) / (cd->params.blksize); + + /*******************************************************\ + * Fill out the scsi command * + \*******************************************************/ + bzero(&cmd, sizeof(cmd)); + cmd.op_code = READ_BIG; + cmd.addr_3 = (blkno & 0xff000000) >> 24; + cmd.addr_2 = (blkno & 0xff0000) >> 16; + cmd.addr_1 = (blkno & 0xff00) >> 8; + cmd.addr_0 = blkno & 0xff; + cmd.length2 = (nblk & 0xff00) >> 8; + cmd.length1 = (nblk & 0xff); + /*******************************************************\ + * Fill out the scsi_xfer structure * + * Note: we cannot sleep as we may be an interrupt * + \*******************************************************/ + xs->flags |= SCSI_NOSLEEP; + xs->adapter = cd->ctlr; + xs->targ = cd->targ; + xs->lu = cd->lu; + xs->retries = CD_RETRIES; + xs->timeout = 10000;/* 10000 millisecs for a disk !*/ + xs->cmd = (struct scsi_generic *)&cmd; + xs->cmdlen = sizeof(cmd); + xs->resid = bp->b_bcount; + xs->when_done = cd_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; + xs->error = XS_NOERROR; + xs->bp = bp; + xs->data = (u_char *)bp->b_un.b_addr; + xs->datalen = bp->b_bcount; + + /*******************************************************\ + * Pass all this info to the scsi driver. * + \*******************************************************/ + if ( (*(cd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED) + { + printf("cd%d: oops not queued",unit); + goto bad; + } + cdqueues++; + return; +bad: xs->error = XS_DRIVER_STUFFUP; + cd_done(unit,xs); +} + +/*******************************************************\ +* This routine is called by the scsi interrupt when * +* the transfer is complete. (or failed) * +\*******************************************************/ +int cd_done(unit,xs) +int unit; +struct scsi_xfer *xs; +{ + struct buf *bp; + int retval; + + if(scsi_debug & PRINTROUTINES) printf("cd_done%d ",unit); + if (! (xs->flags & INUSE)) /* paranoia always pays off */ + panic("scsi_xfer not in use!"); + if(bp = xs->bp) + { + switch(xs->error) + { + case XS_NOERROR: + bp->b_error = 0; + bp->b_resid = 0; + break; + + case XS_SENSE: + retval = (cd_interpret_sense(unit,xs)); + if(retval) + { + bp->b_flags |= B_ERROR; + bp->b_error = retval; + } + break; + + case XS_TIMEOUT: + printf("cd%d timeout\n",unit); + + case XS_BUSY: + /***********************************\ + * Just resubmit it straight back to * + * the SCSI driver to try it again * + \***********************************/ + if(xs->retries--) + { + xs->error = XS_NOERROR; + xs->flags &= ~ITSDONE; + if ( (*(cd_data[unit].sc_sw->scsi_cmd))(xs) + == SUCCESSFULLY_QUEUED) + { /* shhh! don't wake the job, ok? */ + /* don't tell cdstart either, */ + return; + } + /* xs->error is set by the scsi driver */ + } /* Fall through */ + + case XS_DRIVER_STUFFUP: + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + break; + default: + printf("cd%d: unknown error category from scsi driver\n" + ,unit); + } + biodone(bp); + cd_free_xs(unit,xs,0); + cdstart(unit); /* If there's anything waiting.. do it */ + } + else /* special has finished */ + { + wakeup(xs); + } +} +/*******************************************************\ +* Perform special action on behalf of the user * +* Knows about the internals of this device * +\*******************************************************/ +cdioctl(dev_t dev, int cmd, caddr_t addr, int flag) +{ + int error = 0; + unsigned int opri; + unsigned char unit, part; + register struct cd_data *cd; + + + /*******************************************************\ + * Find the device that the user is talking about * + \*******************************************************/ + unit = UNIT(dev); + part = PARTITION(dev); + cd = &cd_data[unit]; + if(scsi_debug & PRINTROUTINES) printf("cdioctl%d ",unit); + + /*******************************************************\ + * If the device is not valid.. abandon ship * + \*******************************************************/ + if (!(cd_data[unit].flags & CDVALID)) + return(EIO); + switch(cmd) + { + + case DIOCSBAD: + error = EINVAL; + break; + + case DIOCGDINFO: + *(struct disklabel *)addr = cd->disklabel; + break; + + case DIOCGPART: + ((struct partinfo *)addr)->disklab = &cd->disklabel; + ((struct partinfo *)addr)->part = + &cd->disklabel.d_partitions[PARTITION(dev)]; + break; + + case DIOCWDINFO: + case DIOCSDINFO: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = setdisklabel(&cd->disklabel, + (struct disklabel *)addr, + /*(cd->flags & DKFL_BSDLABEL) ? cd->openparts : */0, + 0); + if (error == 0) { + cd->flags |= CDHAVELABEL; + } + break; + + case DIOCWLABEL: + error = EBADF; + break; + + case CDIOCPLAYTRACKS: + { + struct ioc_play_track *args + = (struct ioc_play_track *)addr; + struct cd_mode_data data; + if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + break; + data.page.audio.sotc = 0; + data.page.audio.immed = 1; + if(error = cd_set_mode(unit,&data)) + break; + return(cd_play_tracks(unit + ,args->start_track + ,args->start_index + ,args->end_track + ,args->end_index + )); + } + break; + case CDIOCPLAYBLOCKS: + { + struct ioc_play_blocks *args + = (struct ioc_play_blocks *)addr; + struct cd_mode_data data; + if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + break; + data.page.audio.sotc = 0; + data.page.audio.immed = 1; + if(error = cd_set_mode(unit,&data)) + break; + return(cd_play(unit,args->blk,args->len)); + + + } + break; + case CDIOCREADSUBCHANNEL: + { + struct ioc_read_subchannel *args + = (struct ioc_read_subchannel *)addr; + struct cd_sub_channel_info data; + int len=args->data_len; + if(len>sizeof(data)|| + len<sizeof(struct cd_sub_channel_header)) { + error=EINVAL; + break; + } + if(error = cd_read_subchannel(unit,args->address_format, + args->data_format,args->track,&data,len)) { + break; + } + len=MIN(len,((data.header.data_len[0]<<8)+data.header.data_len[1]+ + sizeof(struct cd_sub_channel_header))); + if(copyout(&data,args->data,len)!=0) { + error=EFAULT; + } + } + break; + case CDIOREADTOCHEADER: + { + struct ioc_toc_header th; + if( error = cd_read_toc(unit,0,0,&th,sizeof(th))) + break; + th.len=(th.len&0xff)<<8+((th.len>>8)&0xff); + bcopy(&th,addr,sizeof(th)); + } + break; + case CDIOREADTOCENTRYS: + { + struct ioc_read_toc_entry *te= + (struct ioc_read_toc_entry *)addr; + struct cd_toc_entry data[65]; + struct ioc_toc_header *th; + int len=te->data_len; + th=(struct ioc_toc_header *)data; + + if(len>sizeof(data) || len<sizeof(struct cd_toc_entry)) { + error=EINVAL; + break; + } + if(error = cd_read_toc(unit,te->address_format, + te->starting_track, + data, + len)) + break; + len=MIN(len,((((th->len&0xff)<<8)+((th->len>>8)))+ + sizeof(*th))); + if(copyout(th,te->data,len)!=0) { + error=EFAULT; + } + + } + break; + case CDIOCSETPATCH: + { + struct ioc_patch *arg = (struct ioc_patch *)addr; + struct cd_mode_data data; + if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + break; + data.page.audio.port[LEFT_PORT].channels = arg->patch[0]; + data.page.audio.port[RIGHT_PORT].channels = arg->patch[1]; + data.page.audio.port[2].channels = arg->patch[2]; + data.page.audio.port[3].channels = arg->patch[3]; + if(error = cd_set_mode(unit,&data)) + break; + } + break; + case CDIOCGETVOL: + { + struct ioc_vol *arg = (struct ioc_vol *)addr; + struct cd_mode_data data; + if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + break; + arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume; + arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume; + arg->vol[2] = data.page.audio.port[2].volume; + arg->vol[3] = data.page.audio.port[3].volume; + } + break; + case CDIOCSETVOL: + { + struct ioc_vol *arg = (struct ioc_vol *)addr; + struct cd_mode_data data; + if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + break; + data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT]; + data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT]; + data.page.audio.port[2].volume = arg->vol[2]; + data.page.audio.port[3].volume = arg->vol[3]; + if(error = cd_set_mode(unit,&data)) + break; + } + break; + case CDIOCSETMONO: + { + struct ioc_vol *arg = (struct ioc_vol *)addr; + struct cd_mode_data data; + if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + break; + data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL|4|8; + data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL; + data.page.audio.port[2].channels = 0; + data.page.audio.port[3].channels = 0; + if(error = cd_set_mode(unit,&data)) + break; + } + break; + case CDIOCSETSTERIO: + { + struct ioc_vol *arg = (struct ioc_vol *)addr; + struct cd_mode_data data; + if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + break; + data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL; + data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; + data.page.audio.port[2].channels = 0; + data.page.audio.port[3].channels = 0; + if(error = cd_set_mode(unit,&data)) + break; + } + break; + case CDIOCSETMUTE: + { + struct ioc_vol *arg = (struct ioc_vol *)addr; + struct cd_mode_data data; + if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + break; + data.page.audio.port[LEFT_PORT].channels = 0; + data.page.audio.port[RIGHT_PORT].channels = 0; + data.page.audio.port[2].channels = 0; + data.page.audio.port[3].channels = 0; + if(error = cd_set_mode(unit,&data)) + break; + } + break; + case CDIOCSETLEFT: + { + struct ioc_vol *arg = (struct ioc_vol *)addr; + struct cd_mode_data data; + if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + break; + data.page.audio.port[LEFT_PORT].channels = 15; + data.page.audio.port[RIGHT_PORT].channels = 15; + data.page.audio.port[2].channels = 15; + data.page.audio.port[3].channels = 15; + if(error = cd_set_mode(unit,&data)) + break; + } + break; + case CDIOCSETRIGHT: + { + struct ioc_vol *arg = (struct ioc_vol *)addr; + struct cd_mode_data data; + if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + break; + data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL; + data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; + data.page.audio.port[2].channels = 0; + data.page.audio.port[3].channels = 0; + if(error = cd_set_mode(unit,&data)) + break; + } + break; + case CDIOCRESUME: + error = cd_pause(unit,1); + break; + case CDIOCPAUSE: + error = cd_pause(unit,0); + break; + case CDIOCSTART: + error = cd_start_unit(unit,part,CD_START); + break; + case CDIOCSTOP: + error = cd_start_unit(unit,part,CD_STOP); + break; + case CDIOCEJECT: + error = cd_start_unit(unit,part,CD_EJECT); + break; + case CDIOCSETDEBUG: + scsi_debug = 0xfff; cd_debug = 0xfff; + break; + case CDIOCCLRDEBUG: + scsi_debug = 0; cd_debug = 0; + break; + case CDIOCRESET: + return(cd_reset(unit)); + break; + default: + error = ENOTTY; + break; + } + return (error); +} + + +/*******************************************************\ +* Load the label information on the named device * +* * +* EVENTUALLY take information about different * +* data tracks from the TOC and put it in the disklabel * +\*******************************************************/ +int cdgetdisklabel(unit) +unsigned char unit; +{ + /*unsigned int n, m;*/ + char *errstring; + struct dos_partition *dos_partition_p; + struct cd_data *cd = cd_data + unit; + + /*******************************************************\ + * If the inflo is already loaded, use it * + \*******************************************************/ + if(cd->flags & CDHAVELABEL) return; + + bzero(&cd->disklabel,sizeof(struct disklabel)); + /*******************************************************\ + * make partition 3 the whole disk in case of failure * + * then get pdinfo * + \*******************************************************/ + strncpy(cd->disklabel.d_typename,"scsi cd_rom",16); + strncpy(cd->disklabel.d_packname,"ficticious",16); + cd->disklabel.d_secsize = cd->params.blksize; /* as long as it's not 0 */ + cd->disklabel.d_nsectors = 100; + cd->disklabel.d_ntracks = 1; + cd->disklabel.d_ncylinders = (cd->params.disksize / 100) + 1; + cd->disklabel.d_secpercyl = 100; + cd->disklabel.d_secperunit = cd->params.disksize; + cd->disklabel.d_rpm = 300; + cd->disklabel.d_interleave = 1; + cd->disklabel.d_flags = D_REMOVABLE; + + cd->disklabel.d_npartitions = 1; + cd->disklabel.d_partitions[0].p_offset = 0; + cd->disklabel.d_partitions[0].p_size = cd->params.disksize; + cd->disklabel.d_partitions[0].p_fstype = 9; + + cd->disklabel.d_magic = DISKMAGIC; + cd->disklabel.d_magic2 = DISKMAGIC; + cd->disklabel.d_checksum = dkcksum(&(cd->disklabel)); + + /*******************************************************\ + * Signal to other users and routines that we now have a * + * disklabel that represents the media (maybe) * + \*******************************************************/ + cd->flags |= CDHAVELABEL; + return(ESUCCESS); +} + +/*******************************************************\ +* Find out form the device what it's capacity is * +\*******************************************************/ +cd_size(unit, flags) +{ + struct scsi_read_cd_cap_data rdcap; + struct scsi_read_cd_capacity scsi_cmd; + int size; + int blksize; + + /*******************************************************\ + * make up a scsi command and ask the scsi driver to do * + * it for you. * + \*******************************************************/ + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = READ_CD_CAPACITY; + + /*******************************************************\ + * If the command works, interpret the result as a 4 byte* + * number of blocks * + \*******************************************************/ + if (cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + &rdcap, + sizeof(rdcap), + 2000, + flags) != 0) + { + printf("could not get size of unit %d\n", unit); + return(0); + } else { + size = rdcap.addr_0 + 1 ; + size += rdcap.addr_1 << 8; + size += rdcap.addr_2 << 16; + size += rdcap.addr_3 << 24; + blksize = rdcap.length_0 ; + blksize += rdcap.length_1 << 8; + blksize += rdcap.length_2 << 16; + blksize += rdcap.length_3 << 24; + } + if(cd_debug)printf("cd%d: %d %d byte blocks\n",unit,size,blksize); + cd_data[unit].params.disksize = size; + cd_data[unit].params.blksize = blksize; + return(size); +} + +/*******************************************************\ +* Check with the device that it is ok, (via scsi driver)* +\*******************************************************/ +cd_req_sense(unit, flags) +{ + struct scsi_sense_data sense_data; + struct scsi_sense scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = REQUEST_SENSE; + scsi_cmd.length = sizeof(sense_data); + + if (cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + &sense_data, + sizeof(sense_data), + 2000, + flags) != 0) + { + return(ENXIO); + } + else + return(0); +} + +/*******************************************************\ +* Get the requested page into the buffer given * +\*******************************************************/ +cd_get_mode(unit,data,page) +int unit; +struct cd_mode_data *data; +int page; +{ + struct scsi_mode_sense scsi_cmd; + int retval; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + bzero(data,sizeof(*data)); + scsi_cmd.op_code = MODE_SENSE; + scsi_cmd.page_code = page; + scsi_cmd.length = sizeof(*data) & 0xff; + retval = cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + data, + sizeof(*data), + 20000, /* should be immed */ + 0); + return (retval); +} +/*******************************************************\ +* Get the requested page into the buffer given * +\*******************************************************/ +cd_set_mode(unit,data) +int unit; +struct cd_mode_data *data; +{ + struct scsi_mode_select scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = MODE_SELECT; + scsi_cmd.pf = 1; + scsi_cmd.length = sizeof(*data) & 0xff; + data->header.data_length = 0; + /*show_mem(data,sizeof(*data));/**/ + return (cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + data, + sizeof(*data), + 20000, /* should be immed */ + 0) + ); +} +/*******************************************************\ +* Get scsi driver to send a "start playing" command * +\*******************************************************/ +cd_play(unit,blk,len) +int unit,blk,len; +{ + struct scsi_play scsi_cmd; + int retval; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = PLAY; + scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff; + scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff; + scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff; + scsi_cmd.blk_addr[3] = blk & 0xff; + scsi_cmd.xfer_len[0] = (len >> 8) & 0xff; + scsi_cmd.xfer_len[1] = len & 0xff; + retval = cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 200000, /* should be immed */ + 0); + return(retval); +} +/*******************************************************\ +* Get scsi driver to send a "start playing" command * +\*******************************************************/ +cd_play_big(unit,blk,len) +int unit,blk,len; +{ + struct scsi_play_big scsi_cmd; + int retval; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = PLAY_BIG; + scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff; + scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff; + scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff; + scsi_cmd.blk_addr[3] = blk & 0xff; + scsi_cmd.xfer_len[0] = (len >> 24) & 0xff; + scsi_cmd.xfer_len[1] = (len >> 16) & 0xff; + scsi_cmd.xfer_len[2] = (len >> 8) & 0xff; + scsi_cmd.xfer_len[3] = len & 0xff; + retval = cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 20000, /* should be immed */ + 0); + return(retval); +} +/*******************************************************\ +* Get scsi driver to send a "start playing" command * +\*******************************************************/ +cd_play_tracks(unit,strack,sindex,etrack,eindex) +int unit,strack,sindex,etrack,eindex; +{ + struct scsi_play_track scsi_cmd; + int retval; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = PLAY_TRACK; + scsi_cmd.start_track = strack; + scsi_cmd.start_index = sindex; + scsi_cmd.end_track = etrack; + scsi_cmd.end_index = eindex; + retval = cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 20000, /* should be immed */ + 0); + return(retval); +} +/*******************************************************\ +* Get scsi driver to send a "start up" command * +\*******************************************************/ +cd_pause(unit,go) +int unit,go; +{ + struct scsi_pause scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = PAUSE; + scsi_cmd.resume = go; + + return (cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 2000, + 0)); +} +/*******************************************************\ +* Get scsi driver to send a "start up" command * +\*******************************************************/ +cd_reset(unit) +int unit; +{ + return(cd_scsi_cmd(unit,0,0,0,0,2000,SCSI_RESET)); +} +/*******************************************************\ +* Get scsi driver to send a "start up" command * +\*******************************************************/ +cd_start_unit(unit,part,type) +{ + struct scsi_start_stop scsi_cmd; + + if(type==CD_EJECT && (cd_data[unit].openparts&~(1<<part)) == 0 ) { + cd_prevent_unit(unit,CD_EJECT,0); + } + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = START_STOP; + scsi_cmd.start = type==CD_START?1:0; + scsi_cmd.loej = type==CD_EJECT?1:0; + + if (cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 2000, + 0) != 0) { + return(ENXIO); + } else + return(0); +} +/*******************************************************\ +* Prevent or allow the user to remove the disk * +\*******************************************************/ +cd_prevent_unit(unit,type,flags) +int unit,type,flags; +{ + struct scsi_prevent scsi_cmd; + + if(type==CD_EJECT || type==PR_PREVENT || cd_data[unit].openparts == 0 ) { + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = PREVENT_ALLOW; + scsi_cmd.prevent=type==CD_EJECT?PR_ALLOW:type; + if (cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(struct scsi_prevent), + 0, + 0, + 5000, + 0) != 0) + { + if(!(flags & SCSI_SILENT)) + printf("cannot prevent/allow on cd%d\n", unit); + return(0); + } + } + return(1); +} + +/******************************************************\ +* Read Subchannel * +\******************************************************/ + +cd_read_subchannel(unit,mode,format,track,data,len) +int unit,mode,format,len; +struct cd_sub_channel_info *data; +{ + struct scsi_read_subchannel scsi_cmd; + int error; + + bzero(&scsi_cmd,sizeof(scsi_cmd)); + + scsi_cmd.op_code=READ_SUBCHANNEL; + if(mode==CD_MSF_FORMAT) + scsi_cmd.msf=1; + scsi_cmd.subQ=1; + scsi_cmd.subchan_format=format; + scsi_cmd.track=track; + scsi_cmd.data_len[0]=(len)>>8; + scsi_cmd.data_len[1]=(len)&0xff; + return cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(struct scsi_read_subchannel), + data, + len, + 5000, + 0); +} + +/*******************************************************\ +* Read Table of contents * +\*******************************************************/ +cd_read_toc(unit,mode,start,data,len) +int unit,mode,start,len; +struct cd_toc_entry *data; +{ + struct scsi_read_toc scsi_cmd; + int error; + int ntoc; + + bzero(&scsi_cmd,sizeof(scsi_cmd)); + /*if(len!=sizeof(struct ioc_toc_header)) + ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry); + else*/ + ntoc=len; + + scsi_cmd.op_code=READ_TOC; + if(mode==CD_MSF_FORMAT) + scsi_cmd.msf=1; + scsi_cmd.from_track=start; + scsi_cmd.data_len[0]=(ntoc)>>8; + scsi_cmd.data_len[1]=(ntoc)&0xff; + return cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(struct scsi_read_toc), + data, + len, + 5000, + 0); +} + + +#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) + +/*******************************************************\ +* Get the scsi driver to send a full inquiry to the * +* device and use the results to fill out the disk * +* parameter structure. * +\*******************************************************/ + +int cd_get_parms(unit, flags) +{ + struct cd_data *cd = cd_data + unit; + + /*******************************************************\ + * First check if we have it all loaded * + \*******************************************************/ + if(cd->flags & CDVALID) return(0); + /*******************************************************\ + * give a number of sectors so that sec * trks * cyls * + * is <= disk_size * + \*******************************************************/ + if(cd_size(unit, flags)) + { + cd->flags |= CDVALID; + return(0); + } + else + { + return(ENXIO); + } +} + +/*******************************************************\ +* close the device.. only called if we are the LAST * +* occurence of an open device * +\*******************************************************/ +cdclose(dev) +dev_t dev; +{ + unsigned char unit, part; + unsigned int old_priority; + + unit = UNIT(dev); + part = PARTITION(dev); + if(scsi_debug & TRACEOPENS) + printf("closing cd%d part %d\n",unit,part); + cd_data[unit].partflags[part] &= ~CDOPEN; + cd_data[unit].openparts &= ~(1 << part); + cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT); + return(0); +} + +/*******************************************************\ +* ask the scsi driver to perform a command for us. * +* Call it through the switch table, and tell it which * +* sub-unit we want, and what target and lu we wish to * +* talk to. Also tell it where to find the command * +* how long int is. * +* Also tell it where to read/write the data, and how * +* long the data is supposed to be * +\*******************************************************/ +int cd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) + +int unit,flags; +struct scsi_generic *scsi_cmd; +int cmdlen; +int timeout; +u_char *data_addr; +int datalen; +{ + struct scsi_xfer *xs; + int retval; + int s; + struct cd_data *cd = cd_data + unit; + + if(scsi_debug & PRINTROUTINES) printf("\ncd_scsi_cmd%d ",unit); + if(cd->sc_sw) /* If we have a scsi driver */ + { + xs = cd_get_xs(unit,flags); /* should wait unless booting */ + if(!xs) + { + printf("cd_scsi_cmd%d: controller busy" + " (this should never happen)\n",unit); + return(EBUSY); + } + xs->flags |= INUSE; + /*******************************************************\ + * Fill out the scsi_xfer structure * + \*******************************************************/ + xs->flags |= flags; + xs->adapter = cd->ctlr; + xs->targ = cd->targ; + xs->lu = cd->lu; + xs->retries = CD_RETRIES; + xs->timeout = timeout; + xs->cmd = scsi_cmd; + xs->cmdlen = cmdlen; + xs->data = data_addr; + xs->datalen = datalen; + xs->resid = datalen; + xs->when_done = (flags & SCSI_NOMASK) + ?(int (*)())0 + :cd_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; +retry: xs->error = XS_NOERROR; + xs->bp = 0; + retval = (*(cd->sc_sw->scsi_cmd))(xs); + switch(retval) + { + case SUCCESSFULLY_QUEUED: + s = splbio(); + while(!(xs->flags & ITSDONE)) + sleep(xs,PRIBIO+1); + splx(s); + + case HAD_ERROR: + /*printf("err = %d ",xs->error);*/ + switch(xs->error) + { + case XS_NOERROR: + retval = ESUCCESS; + break; + case XS_SENSE: + retval = (cd_interpret_sense(unit,xs)); + break; + case XS_DRIVER_STUFFUP: + retval = EIO; + break; + + + case XS_BUSY: + case XS_TIMEOUT: + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + goto retry; + } + retval = EIO; + break; + default: + retval = EIO; + printf("cd%d: unknown error category from scsi driver\n" + ,unit); + } + break; + case COMPLETE: + retval = ESUCCESS; + break; + case TRY_AGAIN_LATER: + if(xs->retries-- ) + { + if(tsleep( 0,PRIBIO + 2,"retry",hz * 2)) + { + xs->flags &= ~ITSDONE; + goto retry; + } + } + retval = EIO; + break; + default: + retval = EIO; + } + cd_free_xs(unit,xs,flags); + cdstart(unit); /* check if anything is waiting fr the xs */ + } + else + { + printf("cd%d: not set up\n",unit); + return(EINVAL); + } + return(retval); +} +/***************************************************************\ +* Look at the returned sense and act on the error and detirmine * +* The unix error number to pass back... (0 = report no error) * +\***************************************************************/ + +int cd_interpret_sense(unit,xs) +int unit; +struct scsi_xfer *xs; +{ + struct scsi_sense_data *sense; + int key; + int silent; + + /***************************************************************\ + * If the flags say errs are ok, then always return ok. * + \***************************************************************/ + if (xs->flags & SCSI_ERR_OK) return(ESUCCESS); + silent = (xs->flags & SCSI_SILENT); + + sense = &(xs->sense); + switch(sense->error_class) + { + case 7: + { + key=sense->ext.extended.sense_key; + switch(key) + { + case 0x0: + return(ESUCCESS); + case 0x1: + if(!silent) + { + printf("cd%d: soft error(corrected) ", unit); + if(sense->valid) + { + printf("block no. %d (decimal)", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + printf("\n"); + } + return(ESUCCESS); + case 0x2: + if(!silent)printf("cd%d: not ready\n ", + unit); + return(ENODEV); + case 0x3: + if(!silent) + { + printf("cd%d: medium error ", unit); + if(sense->valid) + { + printf("block no. %d (decimal)", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + printf("\n"); + } + return(EIO); + case 0x4: + if(!silent)printf("cd%d: non-media hardware failure\n ", + unit); + return(EIO); + case 0x5: + if(!silent)printf("cd%d: illegal request\n ", + unit); + return(EINVAL); + case 0x6: + if(!silent)printf("cd%d: Unit attention.\n ", unit); + if (cd_data[unit].openparts) + cd_data[unit].flags &= ~(CDVALID | CDHAVELABEL); + { + return(EIO); + } + return(ESUCCESS); + case 0x7: + if(!silent) + { + printf("cd%d: attempted protection violation ", + unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + printf("\n"); + } + return(EACCES); + case 0x8: + if(!silent) + { + printf("cd%d: block wrong state (worm)\n ", + unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + printf("\n"); + } + return(EIO); + case 0x9: + if(!silent)printf("cd%d: vendor unique\n", + unit); + return(EIO); + case 0xa: + if(!silent)printf("cd%d: copy aborted\n ", + unit); + return(EIO); + case 0xb: + if(!silent)printf("cd%d: command aborted\n ", + unit); + return(EIO); + case 0xc: + if(!silent) + { + printf("cd%d: search returned\n ", + unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + printf("\n"); + } + return(ESUCCESS); + case 0xd: + if(!silent)printf("cd%d: volume overflow\n ", + unit); + return(ENOSPC); + case 0xe: + if(!silent) + { + printf("cd%d: verify miscompare\n ", + unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + printf("\n"); + } + return(EIO); + case 0xf: + if(!silent)printf("cd%d: unknown error key\n ", + unit); + return(EIO); + } + break; + } + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + { + if(!silent)printf("cd%d: error class %d code %d\n", + unit, + sense->error_class, + sense->error_code); + if(sense->valid) + if(!silent)printf("block no. %d (decimal)\n", + (sense->ext.unextended.blockhi <<16) + + (sense->ext.unextended.blockmed <<8) + + (sense->ext.unextended.blocklow )); + } + return(EIO); + } +} + + + + +int +cdsize(dev_t dev) +{ + return (-1); +} + +show_mem(address,num) +unsigned char *address; +int num; +{ + int x,y; + printf("------------------------------"); + for (y = 0; y<num; y += 1) + { + if(!(y % 16)) + printf("\n%03d: ",y); + printf("%02x ",*address++); + } + printf("\n------------------------------\n"); +} + diff --git a/sys/scsi/ch.c b/sys/scsi/ch.c new file mode 100644 index 000000000000..1e7469b66b88 --- /dev/null +++ b/sys/scsi/ch.c @@ -0,0 +1,1015 @@ +/* + */ +/* + * HISTORY + * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * + */ + +#include <sys/types.h> +#include <ch.h> + +#include <sys/param.h> +#include <sys/systm.h> + +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/chio.h> + +#if defined(OSF) +#define SECSIZE 512 +#endif /* defined(OSF) */ + +#include <scsi/scsi_all.h> +#include <scsi/scsi_changer.h> +#include <scsi/scsiconf.h> + + +struct scsi_xfer ch_scsi_xfer[NCH]; +int ch_xfer_block_wait[NCH]; + + +#define PAGESIZ 4096 +#define STQSIZE 4 +#define CH_RETRIES 4 + + +#define MODE(z) ( (minor(z) & 0x0F) ) +#define UNIT(z) ( (minor(z) >> 4) ) + +#ifndef MACH +#define ESUCCESS 0 +#endif MACH + +int ch_info_valid[NCH]; /* the info about the device is valid */ +int ch_initialized[NCH] ; +int ch_debug = 1; + +int chattach(); +int ch_done(); +struct ch_data +{ + int flags; + struct scsi_switch *sc_sw; /* address of scsi low level switch */ + int ctlr; /* so they know which one we want */ + int targ; /* our scsi target ID */ + int lu; /* out scsi lu */ + short chmo; /* Offset of first CHM */ + short chms; /* No. of CHM */ + short slots; /* No. of Storage Elements */ + short sloto; /* Offset of first SE */ + short imexs; /* No. of Import/Export Slots */ + short imexo; /* Offset of first IM/EX */ + short drives; /* No. of CTS */ + short driveo; /* Offset of first CTS */ + short rot; /* CHM can rotate */ + u_long op_matrix; /* possible opertaions */ + u_short lsterr; /* details of lasterror */ + u_char stor; /* posible Storage locations */ +}ch_data[NCH]; + +#define CH_OPEN 0x01 +#define CH_KNOWN 0x02 + +static int next_ch_unit = 0; +/***********************************************************************\ +* The routine called by the low level scsi routine when it discovers * +* A device suitable for this driver * +\***********************************************************************/ + +int chattach(ctlr,targ,lu,scsi_switch) +struct scsi_switch *scsi_switch; +{ + int unit,i,stat; + unsigned char *tbl; + + if(scsi_debug & PRINTROUTINES) printf("chattach: "); + /*******************************************************\ + * Check we have the resources for another drive * + \*******************************************************/ + unit = next_ch_unit++; + if( unit >= NCH) + { + printf("Too many scsi changers..(%d > %d) reconfigure kernel",(unit + 1),NCH); + return(0); + } + /*******************************************************\ + * Store information needed to contact our base driver * + \*******************************************************/ + ch_data[unit].sc_sw = scsi_switch; + ch_data[unit].ctlr = ctlr; + ch_data[unit].targ = targ; + ch_data[unit].lu = lu; + + /*******************************************************\ + * Use the subdriver to request information regarding * + * the drive. We cannot use interrupts yet, so the * + * request must specify this. * + \*******************************************************/ + if((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT*/))) + { + printf(" ch%d: scsi changer, %d slot(s) %d drive(s) %d arm(s) %d i/e-slot(s) \n", + unit, ch_data[unit].slots, ch_data[unit].drives, ch_data[unit].chms, ch_data[unit].imexs); + stat=CH_KNOWN; + } + else + { + printf(" ch%d: scsi changer :- offline\n", unit); + stat=CH_OPEN; + } + ch_initialized[unit] = stat; + + return; + +} + + + +/*******************************************************\ +* open the device. * +\*******************************************************/ +chopen(dev) +{ + int errcode = 0; + int unit,mode; + + unit = UNIT(dev); + mode = MODE(dev); + + /*******************************************************\ + * Check the unit is legal * + \*******************************************************/ + if ( unit >= NCH ) + { + printf("ch %d > %d\n",unit,NCH); + errcode = ENXIO; + return(errcode); + } + /*******************************************************\ + * Only allow one at a time * + \*******************************************************/ + if(ch_data[unit].flags & CH_OPEN) + { + printf("CH%d already open\n",unit); + errcode = ENXIO; + goto bad; + } + + if(ch_debug||(scsi_debug & (PRINTROUTINES | TRACEOPENS))) + printf("chopen: dev=0x%x (unit %d (of %d))\n" + , dev, unit, NCH); + /*******************************************************\ + * Make sure the device has been initialised * + \*******************************************************/ + + if (!ch_initialized[unit]) + return(ENXIO); + if (ch_initialized[unit]!=CH_KNOWN) { + if((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT*/))) + { + ch_initialized[unit]=CH_KNOWN; + } + else + { + printf(" ch%d: scsi changer :- offline\n", unit); + return(ENXIO); + } + } + /*******************************************************\ + * Check that it is still responding and ok. * + \*******************************************************/ + + if(ch_debug || (scsi_debug & TRACEOPENS)) + printf("device is "); + if (!(ch_req_sense(unit, 0))) + { + errcode = ENXIO; + if(ch_debug || (scsi_debug & TRACEOPENS)) + printf("not responding\n"); + goto bad; + } + if(ch_debug || (scsi_debug & TRACEOPENS)) + printf("ok\n"); + + if(!(ch_test_ready(unit,0))) + { + printf("ch%d not ready\n",unit); + return(EIO); + } + + ch_info_valid[unit] = TRUE; + + /*******************************************************\ + * Load the physical device parameters * + \*******************************************************/ + + ch_data[unit].flags = CH_OPEN; + return(errcode); +bad: + return(errcode); +} + +/*******************************************************\ +* close the device.. only called if we are the LAST * +* occurence of an open device * +\*******************************************************/ +chclose(dev) +{ + unsigned char unit,mode; + + unit = UNIT(dev); + mode = MODE(dev); + + if(scsi_debug & TRACEOPENS) + printf("Closing device"); + ch_data[unit].flags = 0; + return(0); +} + + + +/***************************************************************\ +* chstart * +* This routine is also called after other non-queued requests * +* have been made of the scsi driver, to ensure that the queue * +* continues to be drained. * +\***************************************************************/ +/* chstart() is called at splbio */ +chstart(unit) +{ + int drivecount; + register struct buf *bp = 0; + register struct buf *dp; + struct scsi_xfer *xs; + int blkno, nblk; + + + if(scsi_debug & PRINTROUTINES) printf("chstart%d ",unit); + /*******************************************************\ + * See if there is a buf to do and we are not already * + * doing one * + \*******************************************************/ + xs=&ch_scsi_xfer[unit]; + if(xs->flags & INUSE) + { + return; /* unit already underway */ + } + if(ch_xfer_block_wait[unit]) /* a special awaits, let it proceed first */ + { + wakeup(&ch_xfer_block_wait[unit]); + return; + } + + return; + +} + + +/*******************************************************\ +* This routine is called by the scsi interrupt when * +* the transfer is complete. +\*******************************************************/ +int ch_done(unit,xs) +int unit; +struct scsi_xfer *xs; +{ + struct buf *bp; + int retval; + + if(ch_debug||(scsi_debug & PRINTROUTINES)) printf("ch_done%d ",unit); + if (! (xs->flags & INUSE)) + panic("scsi_xfer not in use!"); + wakeup(xs); +} +/*******************************************************\ +* Perform special action on behalf of the user * +* Knows about the internals of this device * +\*******************************************************/ +chioctl(dev, cmd, arg, mode) +dev_t dev; +int cmd; +caddr_t arg; +{ + /* struct ch_cmd_buf *args;*/ + union scsi_cmd *scsi_cmd; + register i,j; + unsigned int opri; + int errcode = 0; + unsigned char unit; + int number,flags,ret; + + /*******************************************************\ + * Find the device that the user is talking about * + \*******************************************************/ + flags = 0; /* give error messages, act on errors etc. */ + unit = UNIT(dev); + + switch(cmd) + { + case CHIOOP: { + struct chop *ch=(struct chop *) arg; + if (ch_debug) + printf("[chtape_chop: %x]\n", ch->ch_op); + + switch ((short)(ch->ch_op)) { + case CHGETPARAM: + ch->u.getparam.chmo= ch_data[unit].chmo; + ch->u.getparam.chms= ch_data[unit].chms; + ch->u.getparam.sloto= ch_data[unit].sloto; + ch->u.getparam.slots= ch_data[unit].slots; + ch->u.getparam.imexo= ch_data[unit].imexo; + ch->u.getparam.imexs= ch_data[unit].imexs; + ch->u.getparam.driveo= ch_data[unit].driveo; + ch->u.getparam.drives= ch_data[unit].drives; + ch->u.getparam.rot= ch_data[unit].rot; + ch->result=0; + return 0; + break; + case CHPOSITION: + return ch_position(unit,&ch->result,ch->u.position.chm, + ch->u.position.to, + flags); + case CHMOVE: + return ch_move(unit,&ch->result, ch->u.position.chm, + ch->u.move.from, ch->u.move.to, + flags); + case CHGETELEM: + return ch_getelem(unit,&ch->result, ch->u.get_elem_stat.type, + ch->u.get_elem_stat.from, &ch->u.get_elem_stat.elem_data, + flags); + default: + return EINVAL; + } + + } + default: + return EINVAL; + } + + return(ret?ESUCCESS:EIO); +} + +ch_getelem(unit,stat,type,from,data,flags) +int unit,from,flags; +short *stat; +char *data; +{ + struct scsi_read_element_status scsi_cmd; + char elbuf[32]; + int ret; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = READ_ELEMENT_STATUS; + scsi_cmd.element_type_code=type; + scsi_cmd.starting_element_addr[0]=(from>>8)&0xff; + scsi_cmd.starting_element_addr[1]=from&0xff; + scsi_cmd.number_of_elements[1]=1; + scsi_cmd.allocation_length[2]=32; + + if ((ret=ch_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + elbuf, + 32, + 100000, + flags) !=ESUCCESS)) { + *stat=ch_data[unit].lsterr; + bcopy(elbuf+16,data,16); + return ret; + } + bcopy(elbuf+16,data,16); /*Just a hack sh */ + return ret; +} + +ch_move(unit,stat,chm,from,to,flags) +int unit,chm,from,to,flags; +short *stat; +{ + struct scsi_move_medium scsi_cmd; + int ret; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = MOVE_MEDIUM; + scsi_cmd.transport_element_address[0]=(chm>>8)&0xff; + scsi_cmd.transport_element_address[1]=chm&0xff; + scsi_cmd.source_address[0]=(from>>8)&0xff; + scsi_cmd.source_address[1]=from&0xff; + scsi_cmd.destination_address[0]=(to>>8)&0xff; + scsi_cmd.destination_address[1]=to&0xff; + scsi_cmd.invert=(chm&CH_INVERT)?1:0; + if ((ret=ch_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + NULL, + 0, + 100000, + flags) !=ESUCCESS)) { + *stat=ch_data[unit].lsterr; + return ret; + } + return ret; +} + +ch_position(unit,stat,chm,to,flags) +int unit,chm,to,flags; +short *stat; +{ + struct scsi_position_to_element scsi_cmd; + int ret; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = POSITION_TO_ELEMENT; + scsi_cmd.transport_element_address[0]=(chm>>8)&0xff; + scsi_cmd.transport_element_address[1]=chm&0xff; + scsi_cmd.source_address[0]=(to>>8)&0xff; + scsi_cmd.source_address[1]=to&0xff; + scsi_cmd.invert=(chm&CH_INVERT)?1:0; + if ((ret=ch_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + NULL, + 0, + 100000, + flags) !=ESUCCESS)) { + *stat=ch_data[unit].lsterr; + return ret; + } + return ret; +} + +/*******************************************************\ +* Check with the device that it is ok, (via scsi driver)* +\*******************************************************/ +ch_req_sense(unit, flags) +int flags; +{ + struct scsi_sense_data sense; + struct scsi_sense scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = REQUEST_SENSE; + scsi_cmd.length = sizeof(sense); + + if (ch_scsi_cmd(unit, + &scsi_cmd, + sizeof(struct scsi_sense), + &sense, + sizeof(sense), + 100000, + flags | SCSI_DATA_IN) != 0) + { + return(FALSE); + } + else + return(TRUE); +} + +/*******************************************************\ +* Get scsi driver to send a "are you ready" command * +\*******************************************************/ +ch_test_ready(unit,flags) +int unit,flags; +{ + struct scsi_test_unit_ready scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = TEST_UNIT_READY; + + if (ch_scsi_cmd(unit, + &scsi_cmd, + sizeof(struct scsi_test_unit_ready), + 0, + 0, + 100000, + flags) != 0) { + return(FALSE); + } else + return(TRUE); +} + + +#ifdef __STDC__ +#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) +#else +#define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 ) +#endif + +/*******************************************************\ +* Get the scsi driver to send a full inquiry to the * +* device and use the results to fill out the global * +* parameter structure. * +\*******************************************************/ +ch_mode_sense(unit, flags) +int unit,flags; +{ + struct scsi_mode_sense scsi_cmd; + u_char scsi_sense[128]; /* Can't use scsi_mode_sense_data because of */ + /* missing block descriptor */ + u_char *b; + int i,l; + + /*******************************************************\ + * First check if we have it all loaded * + \*******************************************************/ + if (ch_info_valid[unit]==CH_KNOWN) return(TRUE); + /*******************************************************\ + * First do a mode sense * + \*******************************************************/ + ch_info_valid[unit] &= ~CH_KNOWN; + for(l=1;l>=0;l--) { + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = MODE_SENSE; + scsi_cmd.dbd = l; + scsi_cmd.page_code = 0x3f; /* All Pages */ + scsi_cmd.length = sizeof(scsi_sense); + /*******************************************************\ + * do the command, but we don't need the results * + * just print them for our interest's sake * + \*******************************************************/ + if (ch_scsi_cmd(unit, + &scsi_cmd, + sizeof(struct scsi_mode_sense), + &scsi_sense, + sizeof(scsi_sense), + 5000, + flags | SCSI_DATA_IN) == 0) { + ch_info_valid[unit] = CH_KNOWN; + break; + } + } + if (ch_info_valid[unit]!=CH_KNOWN) { + if(!(flags & SCSI_SILENT)) + printf("could not mode sense for unit %d\n", unit); + return(FALSE); + } + l=scsi_sense[0]-3; + b=&scsi_sense[4]; + /*****************************\ + * To avoid alignment problems * + \*****************************/ +/*FIX THIS FOR MSB */ +#define p2copy(valp) (valp[1]+ (valp[0]<<8));valp+=2 +#define p4copy(valp) (valp[3]+ (valp[2]<<8) + (valp[1]<<16) + (valp[0]<<24));valp+=4 +#if 0 + printf("\nmode_sense %d\n",l); + for(i=0;i<l+4;i++) { + printf("%x%c",scsi_sense[i],i%8==7?'\n':':'); + } + printf("\n"); +#endif + for(i=0;i<l;) { + int pc=(*b++)&0x3f; + int pl=*b++; + u_char *bb=b; + switch(pc) { + case 0x1d: + ch_data[unit].chmo =p2copy(bb); + ch_data[unit].chms =p2copy(bb); + ch_data[unit].sloto =p2copy(bb); + ch_data[unit].slots =p2copy(bb); + ch_data[unit].imexo =p2copy(bb); + ch_data[unit].imexs =p2copy(bb); + ch_data[unit].driveo =p2copy(bb); + ch_data[unit].drives =p2copy(bb); + break; + case 0x1e: + ch_data[unit].rot = (*b)&1; + break; + case 0x1f: + ch_data[unit].stor = *b&0xf; + bb+=2; + ch_data[unit].stor =p4copy(bb); + break; + default: + break; + } + b+=pl; + i+=pl+2; + } + if (ch_debug) + { + printf("unit %d: cht(%d-%d)slot(%d-%d)imex(%d-%d)cts(%d-%d) %s rotate\n", + unit, + ch_data[unit].chmo, + ch_data[unit].chms, + ch_data[unit].sloto, + ch_data[unit].slots, + ch_data[unit].imexo, + ch_data[unit].imexs, + ch_data[unit].driveo, + ch_data[unit].drives, + ch_data[unit].rot?"can":"can't"); + } + return(TRUE); +} + +/*******************************************************\ +* ask the scsi driver to perform a command for us. * +* Call it through the switch table, and tell it which * +* sub-unit we want, and what target and lu we wish to * +* talk to. Also tell it where to find the command * +* how long int is. * +* Also tell it where to read/write the data, and how * +* long the data is supposed to be * +\*******************************************************/ +int ch_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) + +int unit,flags; +struct scsi_generic *scsi_cmd; +int cmdlen; +int timeout; +u_char *data_addr; +int datalen; +{ + struct scsi_xfer *xs; + int retval; + int s; + + if(ch_debug||(scsi_debug & PRINTROUTINES)) printf("\nch_scsi_cmd%d %x", + unit,scsi_cmd->opcode); + if(ch_data[unit].sc_sw) /* If we have a scsi driver */ + { + + xs = &(ch_scsi_xfer[unit]); + if(!(flags & SCSI_NOMASK)) + s = splbio(); + ch_xfer_block_wait[unit]++; /* there is someone waiting */ + while (xs->flags & INUSE) + { + sleep(&ch_xfer_block_wait[unit],PRIBIO+1); + } + ch_xfer_block_wait[unit]--; + xs->flags = INUSE; + if(!(flags & SCSI_NOMASK)) + splx(s); + + /*******************************************************\ + * Fill out the scsi_xfer structure * + \*******************************************************/ + xs->flags |= flags; + xs->adapter = ch_data[unit].ctlr; + xs->targ = ch_data[unit].targ; + xs->lu = ch_data[unit].lu; + xs->retries = CH_RETRIES; + xs->timeout = timeout; + xs->cmd = scsi_cmd; + xs->cmdlen = cmdlen; + xs->data = data_addr; + xs->datalen = datalen; + xs->resid = datalen; + xs->when_done = (flags & SCSI_NOMASK) + ?(int (*)())0 + :ch_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; +retry: xs->error = XS_NOERROR; + xs->bp = 0; + ch_data[unit].lsterr=0; + retval = (*(ch_data[unit].sc_sw->scsi_cmd))(xs); + switch(retval) + { + case SUCCESSFULLY_QUEUED: + while(!(xs->flags & ITSDONE)) + sleep(xs,PRIBIO+1); + + case HAD_ERROR: + case COMPLETE: + switch(xs->error) + { + case XS_NOERROR: + retval = ESUCCESS; + break; + case XS_SENSE: + retval = (ch_interpret_sense(unit,xs)); + break; + case XS_DRIVER_STUFFUP: + retval = EIO; + break; + case XS_TIMEOUT: + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + goto retry; + } + retval = EIO; + break; + case XS_BUSY: + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + goto retry; + } + retval = EIO; + break; + default: + retval = EIO; + printf("st%d: unknown error category from scsi driver\n" + ,unit); + break; + } + break; + case TRY_AGAIN_LATER: + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + goto retry; + } + retval = EIO; + break; + default: + retval = EIO; + } + xs->flags = 0; /* it's free! */ + chstart(unit); + } + else + { + printf("chd: not set up\n",unit); + return(EINVAL); + } + return(retval); +} +/***************************************************************\ +* Look at the returned sense and act on the error and detirmine * +* The unix error number to pass back... (0 = report no error) * +\***************************************************************/ + +int ch_interpret_sense(unit,xs) +int unit; +struct scsi_xfer *xs; +{ + struct scsi_sense_data *sense; + int key; + int silent = xs->flags & SCSI_SILENT; + + /***************************************************************\ + * If errors are ok, report a success * + \***************************************************************/ + if(xs->flags & SCSI_ERR_OK) return(ESUCCESS); + + /***************************************************************\ + * Get the sense fields and work out what CLASS * + \***************************************************************/ + sense = &(xs->sense); + switch(sense->error_class) + { + /***************************************************************\ + * If it's class 7, use the extended stuff and interpret the key * + \***************************************************************/ + case 7: + { + key=sense->ext.extended.sense_key; + if(sense->ext.extended.ili) + if(!silent) + { + printf("length error "); + } + if(sense->valid) + xs->resid = ntohl(*((long *)sense->ext.extended.info)); + if(xs->bp) + { + xs->bp->b_flags |= B_ERROR; + return(ESUCCESS); + } + if(sense->ext.extended.eom) + if(!silent) printf("end of medium "); + if(sense->ext.extended.filemark) + if(!silent) printf("filemark "); + if(ch_debug) + { + printf("code%x class%x valid%x\n" + ,sense->error_code + ,sense->error_class + ,sense->valid); + printf("seg%x key%x ili%x eom%x fmark%x\n" + ,sense->ext.extended.segment + ,sense->ext.extended.sense_key + ,sense->ext.extended.ili + ,sense->ext.extended.eom + ,sense->ext.extended.filemark); + printf("info: %x %x %x %x followed by %d extra bytes\n" + ,sense->ext.extended.info[0] + ,sense->ext.extended.info[1] + ,sense->ext.extended.info[2] + ,sense->ext.extended.info[3] + ,sense->ext.extended.extra_len); + printf("extra: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n" + ,sense->ext.extended.extra_bytes[0] + ,sense->ext.extended.extra_bytes[1] + ,sense->ext.extended.extra_bytes[2] + ,sense->ext.extended.extra_bytes[3] + ,sense->ext.extended.extra_bytes[4] + ,sense->ext.extended.extra_bytes[5] + ,sense->ext.extended.extra_bytes[6] + ,sense->ext.extended.extra_bytes[7] + ,sense->ext.extended.extra_bytes[8] + ,sense->ext.extended.extra_bytes[9] + ,sense->ext.extended.extra_bytes[10] + ,sense->ext.extended.extra_bytes[11] + ,sense->ext.extended.extra_bytes[12] + ,sense->ext.extended.extra_bytes[13] + ,sense->ext.extended.extra_bytes[14] + ,sense->ext.extended.extra_bytes[15]); + + } + switch(key) + { + case 0x0: + return(ESUCCESS); + case 0x1: + if(!silent) + { + printf("st%d: soft error(corrected) ", unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + else + { + printf("\n"); + } + } + return(ESUCCESS); + case 0x2: + if(!silent) printf("st%d: not ready\n ", unit); + ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| + sense->ext.extended.info[13] ; + return(ENODEV); + case 0x3: + if(!silent) + { + printf("st%d: medium error ", unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + else + { + printf("\n"); + } + } + return(EIO); + case 0x4: + if(!silent) printf("st%d: non-media hardware failure\n ", + unit); + ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| + sense->ext.extended.info[13] ; + return(EIO); + case 0x5: + if(!silent) printf("st%d: illegal request\n ", unit); + ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| + sense->ext.extended.info[13] ; + return(EINVAL); + case 0x6: + if(!silent) printf("st%d: Unit attention.\n ", unit); + ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| + sense->ext.extended.info[13] ; + ch_info_valid[unit] = FALSE; + if (ch_data[unit].flags & CH_OPEN) /* TEMP!!!! */ + return(EIO); + else + return(ESUCCESS); + case 0x7: + if(!silent) + { + printf("st%d: attempted protection violation " + , unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + else + { + printf("\n"); + } + } + return(EACCES); + case 0x8: + if(!silent) + { + printf("st%d: block wrong state (worm)\n " + , unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + else + { + printf("\n"); + } + } + return(EIO); + case 0x9: + if(!silent) printf("st%d: vendor unique\n", + unit); + return(EIO); + case 0xa: + if(!silent) printf("st%d: copy aborted\n ", + unit); + return(EIO); + case 0xb: + if(!silent) printf("st%d: command aborted\n ", + unit); + ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| + sense->ext.extended.info[13] ; + return(EIO); + case 0xc: + if(!silent) + { + printf("st%d: search returned\n ", unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + else + { + printf("\n"); + } + } + return(ESUCCESS); + case 0xd: + if(!silent) printf("st%d: volume overflow\n ", + unit); + return(ENOSPC); + case 0xe: + if(!silent) + { + printf("st%d: verify miscompare\n ", unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + else + { + printf("\n"); + } + } + return(EIO); + case 0xf: + if(!silent) printf("st%d: unknown error key\n ", + unit); + return(EIO); + } + break; + } + /***************************************************************\ + * If it's NOT class 7, just report it. * + \***************************************************************/ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + { + if(!silent) printf("st%d: error class %d code %d\n", + unit, + sense->error_class, + sense->error_code); + if(sense->valid) + if(!silent) printf("block no. %d (decimal)\n", + (sense->ext.unextended.blockhi <<16), + + (sense->ext.unextended.blockmed <<8), + + (sense->ext.unextended.blocklow )); + } + return(EIO); + } +} + + + diff --git a/sys/scsi/scsi_all.h b/sys/scsi/scsi_all.h new file mode 100644 index 000000000000..430c70c3d6e5 --- /dev/null +++ b/sys/scsi/scsi_all.h @@ -0,0 +1,373 @@ +/* + * HISTORY + * $Log: scsi_all.h,v $ + * Revision 1.2 1992/11/20 23:07:13 julian + * add a definition for device type T_NODEVICE + * + * Revision 1.1 1992/09/26 22:14:02 julian + * Initial revision + * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * + */ + +/* + * SCSI general interface description + */ + + +/* + * Largely written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + */ + +/* + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + */ + +/* + * SCSI command format + */ + + +struct scsi_generic +{ + u_char opcode; + u_char bytes[11]; +}; + +struct scsi_test_unit_ready +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char unused[3]; + u_char link:1; + u_char flag:4; + u_char :3; +}; + +struct scsi_send_diag +{ + u_char op_code; + u_char uol:1; + u_char dol:1; + u_char selftest:1; + u_char :1; + u_char pf:1; + u_char lun:3; + u_char unused[1]; + u_char paramlen[2]; + u_char link:1; + u_char flag:4; + u_char :3; +}; + +struct scsi_sense +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char unused[2]; + u_char length; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_inquiry +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char unused[2]; + u_char length; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_mode_sense +{ + u_char op_code; + u_char :3; + u_char dbd:1; + u_char rsvd:1; + u_char lun:3; + u_char page_code:6; + u_char page_ctrl:2; + u_char unused; + u_char length; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_mode_sense_big +{ + u_char op_code; + u_char :3; + u_char dbd:1; + u_char rsvd:1; + u_char lun:3; + u_char page_code:6; + u_char page_ctrl:2; + u_char unused[4]; + u_char length[2]; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_mode_select +{ + u_char op_code; + u_char sp:1; + u_char :3; + u_char pf:1; + u_char lun:3; + u_char unused[2]; + u_char length; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_mode_select_big +{ + u_char op_code; + u_char sp:1; + u_char :3; + u_char pf:1; + u_char lun:3; + u_char unused[5]; + u_char length[2]; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_reserve +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char unused[2]; + u_char length; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_release +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char unused[2]; + u_char length; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_prevent +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char unused[2]; + u_char prevent:1; + u_char :7; + u_char link:1; + u_char flag:1; + u_char :6; +}; +#define PR_PREVENT 1 +#define PR_ALLOW 0 + +/* + * Opcodes + */ + +#define TEST_UNIT_READY 0x00 +#define REQUEST_SENSE 0x03 +#define INQUIRY 0x12 +#define MODE_SELECT 0x15 +#define MODE_SENSE 0x1a +#define START_STOP 0x1b +#define RESERVE 0x16 +#define RELEASE 0x17 +#define PREVENT_ALLOW 0x1e +#define POSITION_TO_ELEMENT 0x2b +#define MODE_SENSE_BIG 0x54 +#define MODE_SELECT_BIG 0x55 +#define MOVE_MEDIUM 0xa5 +#define READ_ELEMENT_STATUS 0xb8 + + +/* + * sense data format + */ +#define T_DIRECT 0 +#define T_SEQUENTIAL 1 +#define T_PRINTER 2 +#define T_PROCESSOR 3 +#define T_WORM 4 +#define T_READONLY 5 +#define T_SCANNER 6 +#define T_OPTICAL 7 +#define T_NODEVICE 0x1F + +#define T_CHANGER 8 +#define T_COMM 9 + +#define T_REMOV 1 +#define T_FIXED 0 + +struct scsi_inquiry_data +{ + u_char device_type:5; + u_char device_qualifier:3; + u_char dev_qual2:7; + u_char removable:1; + u_char ansii_version:3; + u_char :5; + u_char response_format; + u_char additional_length; + u_char unused[2]; + u_char :3; + u_char can_link:1; + u_char can_sync:1; + u_char :3; + char vendor[8]; + char product[16]; + char revision[4]; + u_char extra[8]; +}; + + +struct scsi_sense_data +{ + u_char error_code:4; + u_char error_class:3; + u_char valid:1; + union + { + struct + { + u_char blockhi:5; + u_char vendor:3; + u_char blockmed; + u_char blocklow; + } unextended; + struct + { + u_char segment; + u_char sense_key:4; + u_char :1; + u_char ili:1; + u_char eom:1; + u_char filemark:1; + u_char info[4]; + u_char extra_len; + /* allocate enough room to hold new stuff + u_char cmd_spec_info[4]; + u_char add_sense_code; + u_char add_sense_code_qual; + u_char fru; + u_char sense_key_spec_1:7; + u_char sksv:1; + u_char sense_key_spec_2; + u_char sense_key_spec_3; + ( by increasing 16 to 26 below) */ + u_char extra_bytes[26]; + } extended; + }ext; +}; +struct scsi_sense_data_new +{ + u_char error_code:7; + u_char valid:1; + union + { + struct + { + u_char blockhi:5; + u_char vendor:3; + u_char blockmed; + u_char blocklow; + } unextended; + struct + { + u_char segment; + u_char sense_key:4; + u_char :1; + u_char ili:1; + u_char eom:1; + u_char filemark:1; + u_char info[4]; + u_char extra_len; + u_char cmd_spec_info[4]; + u_char add_sense_code; + u_char add_sense_code_qual; + u_char fru; + u_char sense_key_spec_1:7; + u_char sksv:1; + u_char sense_key_spec_2; + u_char sense_key_spec_3; + u_char extra_bytes[16]; + } extended; + }ext; +}; + +struct blk_desc +{ + u_char density; + u_char nblocks[3]; + u_char reserved; + u_char blklen[3]; +}; + +struct scsi_mode_header +{ + u_char data_length; /* Sense data length */ + u_char medium_type; + u_char dev_spec; + u_char blk_desc_len; +}; + +struct scsi_mode_header_big +{ + u_char data_length[2]; /* Sense data length */ + u_char medium_type; + u_char dev_spec; + u_char unused[2]; + u_char blk_desc_len[2]; +}; + + +/* + * Status Byte + */ +#define SCSI_OK 0x00 +#define SCSI_CHECK 0x02 +#define SCSI_BUSY 0x08 +#define SCSI_INTERM 0x10 diff --git a/sys/scsi/scsi_cd.h b/sys/scsi/scsi_cd.h new file mode 100644 index 000000000000..c35bdff7c06e --- /dev/null +++ b/sys/scsi/scsi_cd.h @@ -0,0 +1,295 @@ +/* + * Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + */ + + + +/* + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + */ + +/* + * SCSI command format + */ + +struct scsi_read_capacity_cd +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char addr_3; /* Most Significant */ + u_char addr_2; + u_char addr_1; + u_char addr_0; /* Least Significant */ + u_char unused[3]; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_pause +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char unused[6]; + u_char resume:1; + u_char :7; + u_char link:1; + u_char flag:1; + u_char :6; +}; +#define PA_PAUSE 1 +#define PA_RESUME 0 + +struct scsi_play_msf +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char unused; + u_char start_m; + u_char start_s; + u_char start_f; + u_char end_m; + u_char end_s; + u_char end_f; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_play_track +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char unused[2]; + u_char start_track; + u_char start_index; + u_char unused1; + u_char end_track; + u_char end_index; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_play +{ + u_char op_code; + u_char reladdr:1; + u_char :4; + u_char lun:3; + u_char blk_addr[4]; + u_char unused; + u_char xfer_len[2]; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_play_big +{ + u_char op_code; + u_char reladdr:1; + u_char :4; + u_char lun:3; + u_char blk_addr[4]; + u_char xfer_len[4]; + u_char unused; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_play_rel_big +{ + u_char op_code; + u_char reladdr:1; + u_char :4; + u_char lun:3; + u_char blk_addr[4]; + u_char xfer_len[4]; + u_char track; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_read_header +{ + u_char op_code; + u_char :1; + u_char msf:1; + u_char :3; + u_char lun:3; + u_char blk_addr[4]; + u_char unused; + u_char data_len[2]; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_read_subchannel +{ + u_char op_code; + u_char :1; + u_char msf:1; + u_char :3; + u_char lun:3; + u_char :6; + u_char subQ:1; + u_char :1; + u_char subchan_format; + u_char unused[2]; + u_char track; + u_char data_len[2]; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_read_toc +{ + u_char op_code; + u_char :1; + u_char msf:1; + u_char :3; + u_char lun:3; + u_char unused[4]; + u_char from_track; + u_char data_len[2]; + u_char link:1; + u_char flag:1; + u_char :6; +}; +; + +struct scsi_read_cd_capacity +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char addr_3; /* Most Significant */ + u_char addr_2; + u_char addr_1; + u_char addr_0; /* Least Significant */ + u_char unused[3]; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +/* + * Opcodes + */ + +#define READ_CD_CAPACITY 0x25 /* slightly different from disk */ +#define READ_SUBCHANNEL 0x42 /* cdrom read Subchannel */ +#define READ_TOC 0x43 /* cdrom read TOC */ +#define READ_HEADER 0x44 /* cdrom read header */ +#define PLAY 0x45 /* cdrom play 'play audio' mode */ +#define PLAY_MSF 0x47 /* cdrom play Min,Sec,Frames mode */ +#define PLAY_TRACK 0x48 /* cdrom play track/index mode */ +#define PLAY_TRACK_REL 0x49 /* cdrom play track/index mode */ +#define PAUSE 0x4b /* cdrom pause in 'play audio' mode */ +#define PLAY_BIG 0xa5 /* cdrom pause in 'play audio' mode */ +#define PLAY_TRACK_REL_BIG 0xa9 /* cdrom play track/index mode */ + + +struct cd_inquiry_data /* in case there is some special info */ +{ + u_char device_type:5; + u_char device_qualifier:3; + u_char dev_qual2:7; + u_char removable:1; + u_char ansii_version:3; + u_char :5; + u_char response_format; + u_char additional_length; + u_char unused[2]; + u_char :3; + u_char can_link:1; + u_char can_sync:1; + u_char :3; + char vendor[8]; + char product[16]; + char revision[4]; + u_char extra[8]; +}; + +struct scsi_read_cd_cap_data +{ + u_char addr_3; /* Most significant */ + u_char addr_2; + u_char addr_1; + u_char addr_0; /* Least significant */ + u_char length_3; /* Most significant */ + u_char length_2; + u_char length_1; + u_char length_0; /* Least significant */ +}; + +union cd_pages +{ +#define AUDIO_PAGE 0x0e + struct audio_page + { + u_char page_code:6; + u_char :1; + u_char ps:1; + u_char param_len; + u_char :1; + u_char sotc:1; + u_char immed:1; + u_char :5; + u_char unused[2]; + u_char format_lba:4; + u_char :3; + u_char apr_valid:1; + u_char lb_per_sec[2]; + struct port_control + { + u_char channels:4; +#define CHANNEL_0 1 +#define CHANNEL_1 2 +#define CHANNEL_2 4 +#define CHANNEL_3 8 +#define LEFT_CHANNEL CHANNEL_0 +#define RIGHT_CHANNEL CHANNEL_1 + u_char :4; + u_char volume; + } port[4]; +#define LEFT_PORT 0 +#define RIGHT_PORT 1 + }audio; +}; + +struct cd_mode_data +{ + struct scsi_mode_header header; + struct blk_desc blk_desc; + union cd_pages page; +}; + diff --git a/sys/scsi/scsi_changer.h b/sys/scsi/scsi_changer.h new file mode 100644 index 000000000000..63a5b1398a29 --- /dev/null +++ b/sys/scsi/scsi_changer.h @@ -0,0 +1,118 @@ +/* + * HISTORY + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * + */ + +/* + * SCSI changer interface description + */ + +/* + * Written by Stefan Grefen (grefen@goofy.zdv.uni-mainz.de soon grefen@convex.com) + * based on the SCSI System by written Julian Elischer (julian@tfs.com) + * for TRW Financial Systems. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + */ + +/* + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + */ + +/* + * SCSI command format + */ +struct scsi_read_element_status +{ + u_char op_code; + u_char element_type_code:4; + u_char voltag:1; + u_char lun:3; + u_char starting_element_addr[2]; + u_char number_of_elements[2]; + u_char resv1; + u_char allocation_length[3]; + u_char resv2; + u_char link:1; + u_char flag:1; + u_char :6; +}; +#define RE_ALL_ELEMENTS 0 +#define RE_MEDIUM_TRANSPORT_ELEMENT 1 +#define RE_STORAGE_ELEMENT 2 +#define RE_IMPORT_EXPORT 3 +#define RE_DATA_TRANSFER_ELEMENT 4 + +struct scsi_move_medium +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char transport_element_address[2]; + u_char source_address[2]; + u_char destination_address[2]; + u_char rsvd[2]; + u_char invert:1; + u_char :7; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_position_to_element +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char transport_element_address[2]; + u_char source_address[2]; + u_char rsvd[2]; + u_char invert:1; + u_char :7; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +/* + * Opcodes + */ +#define POSITION_TO_ELEMENT 0x2b +#define MOVE_MEDIUM 0xa5 +#define READ_ELEMENT_STATUS 0xb8 + +struct scsi_element_status_data +{ + u_char first_element_reported[2]; + u_char number_of_elements_reported[2]; + u_char rsvd; + u_char byte_count_of_report[3]; +}; + +struct element_status_page +{ + u_char element_type_code; + u_char :5; + u_char avoltag:1; + u_char pvoltag:1; + u_char element_descriptor_length[2]; + u_char rsvd; + u_char byte_count_of_descriptor_data[3]; +}; + diff --git a/sys/scsi/scsi_disk.h b/sys/scsi/scsi_disk.h new file mode 100644 index 000000000000..35a3b7837819 --- /dev/null +++ b/sys/scsi/scsi_disk.h @@ -0,0 +1,249 @@ +/* + * HISTORY + * $Log: scsi_disk.h,v $ + * Revision 1.2 1992/10/13 03:14:21 julian + * added the load-eject field in 'start/stop' for removable devices. + * + * Revision 1.1 1992/09/26 22:11:29 julian + * Initial revision + * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * + */ + +/* + * SCSI interface description + */ + +/* + * Some lines of this file comes from a file of the name "scsi.h" + * distributed by OSF as part of mach2.5, + * so the following disclaimer has been kept. + * + * Copyright 1990 by Open Software Foundation, + * Grenoble, FRANCE + * + * 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 OSF or Open Software + * Foundation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. + * + * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL OSF 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. + */ + +/* + * Largely written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + */ + +/* + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + */ + +/* + * SCSI command format + */ + + +struct scsi_reassign_blocks +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char unused[3]; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_rw +{ + u_char op_code; + u_char addr_2:5; /* Most significant */ + u_char lun:3; + u_char addr_1; + u_char addr_0; /* least significant */ + u_char length; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_rw_big +{ + u_char op_code; + u_char rel_addr:1; + u_char :4; /* Most significant */ + u_char lun:3; + u_char addr_3; + u_char addr_2; + u_char addr_1; + u_char addr_0; /* least significant */ + u_char reserved;; + u_char length2; + u_char length1; + u_char link:1; + u_char flag:1; + u_char :4; + u_char vendor:2; +}; + +struct scsi_read_capacity +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char addr_3; /* Most Significant */ + u_char addr_2; + u_char addr_1; + u_char addr_0; /* Least Significant */ + u_char unused[3]; + u_char link:1; + u_char flag:1; + u_char :6; +}; + +struct scsi_start_stop +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char unused[2]; + u_char start:1; + u_char loej:1; + u_char :6; + u_char link:1; + u_char flag:1; + u_char :6; +}; + + + +/* + * Opcodes + */ + +#define REASSIGN_BLOCKS 0x07 +#define READ_COMMAND 0x08 +#define WRITE_COMMAND 0x0a +#define MODE_SELECT 0x15 +#define MODE_SENSE 0x1a +#define START_STOP 0x1b +#define PREVENT_ALLOW 0x1e +#define READ_CAPACITY 0x25 +#define READ_BIG 0x28 +#define WRITE_BIG 0x2a + + + +struct scsi_read_cap_data +{ + u_char addr_3; /* Most significant */ + u_char addr_2; + u_char addr_1; + u_char addr_0; /* Least significant */ + u_char length_3; /* Most significant */ + u_char length_2; + u_char length_1; + u_char length_0; /* Least significant */ +}; + +struct scsi_reassign_blocks_data +{ + u_char reserved[2]; + u_char length_msb; + u_char length_lsb; + struct + { + u_char dlbaddr_3; /* defect logical block address (MSB) */ + u_char dlbaddr_2; + u_char dlbaddr_1; + u_char dlbaddr_0; /* defect logical block address (LSB) */ + } defect_descriptor[1]; +}; + +union disk_pages /* this is the structure copied from osf */ +{ + struct page_disk_format { + u_char pg_code:6; /* page code (should be 3) */ + u_char :2; + u_char pg_length; /* page length (should be 0x16) */ + u_char trk_z_1; /* tracks per zone (MSB) */ + u_char trk_z_0; /* tracks per zone (LSB) */ + u_char alt_sec_1; /* alternate sectors per zone (MSB) */ + u_char alt_sec_0; /* alternate sectors per zone (LSB) */ + u_char alt_trk_z_1; /* alternate tracks per zone (MSB) */ + u_char alt_trk_z_0; /* alternate tracks per zone (LSB) */ + u_char alt_trk_v_1; /* alternate tracks per volume (MSB) */ + u_char alt_trk_v_0; /* alternate tracks per volume (LSB) */ + u_char ph_sec_t_1; /* physical sectors per track (MSB) */ + u_char ph_sec_t_0; /* physical sectors per track (LSB) */ + u_char bytes_s_1; /* bytes per sector (MSB) */ + u_char bytes_s_0; /* bytes per sector (LSB) */ + u_char interleave_1;/* interleave (MSB) */ + u_char interleave_0;/* interleave (LSB) */ + u_char trk_skew_1; /* track skew factor (MSB) */ + u_char trk_skew_0; /* track skew factor (LSB) */ + u_char cyl_skew_1; /* cylinder skew (MSB) */ + u_char cyl_skew_0; /* cylinder skew (LSB) */ + u_char reserved1:4; + u_char surf:1; + u_char rmb:1; + u_char hsec:1; + u_char ssec:1; + u_char reserved2; + u_char reserved3; + } disk_format; + struct page_rigid_geometry { + u_char pg_code:7; /* page code (should be 4) */ + u_char mbone:1; /* must be one */ + u_char pg_length; /* page length (should be 0x16) */ + u_char ncyl_2; /* number of cylinders (MSB) */ + u_char ncyl_1; /* number of cylinders */ + u_char ncyl_0; /* number of cylinders (LSB) */ + u_char nheads; /* number of heads */ + u_char st_cyl_wp_2; /* starting cyl., write precomp (MSB) */ + u_char st_cyl_wp_1; /* starting cyl., write precomp */ + u_char st_cyl_wp_0; /* starting cyl., write precomp (LSB) */ + u_char st_cyl_rwc_2;/* starting cyl., red. write cur (MSB)*/ + u_char st_cyl_rwc_1;/* starting cyl., red. write cur */ + u_char st_cyl_rwc_0;/* starting cyl., red. write cur (LSB)*/ + u_char driv_step_1; /* drive step rate (MSB) */ + u_char driv_step_0; /* drive step rate (LSB) */ + u_char land_zone_2; /* landing zone cylinder (MSB) */ + u_char land_zone_1; /* landing zone cylinder */ + u_char land_zone_0; /* landing zone cylinder (LSB) */ + u_char reserved1; + u_char reserved2; + u_char reserved3; + } rigid_geometry; +} ; diff --git a/sys/scsi/scsi_tape.h b/sys/scsi/scsi_tape.h new file mode 100644 index 000000000000..2b8a82f07460 --- /dev/null +++ b/sys/scsi/scsi_tape.h @@ -0,0 +1,169 @@ +/* + * HISTORY + * $Log: scsi_tape.h,v $ + * Revision 1.2 1993/01/26 18:39:08 julian + * add the 'write protected' bit in the device status struct. + * + * Revision 1.1 1992/09/26 22:10:21 julian + * Initial revision + * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * + */ + +/* + * SCSI tape interface description + */ + +/* + * Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + */ + +/* + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + */ + +/* + * SCSI command format + */ + + +struct scsi_rw_tape +{ + u_char op_code; + u_char fixed:1; + u_char :4; + u_char lun:3; + u_char len[3]; + u_char link:1; + u_char flag:1; + u_char :6; +} rw_tape; + +struct scsi_space +{ + u_char op_code; + u_char code:2; + u_char :3; + u_char lun:3; + u_char number[3]; + u_char link:1; + u_char flag:1; + u_char :6; +} space; +#define SP_BLKS 0 +#define SP_FILEMARKS 1 +#define SP_SEQ_FILEMARKS 2 +#define SP_EOM 3 + +struct scsi_write_filemarks +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char number[3]; + u_char link:1; + u_char flag:1; + u_char :6; +} write_filemarks; + +struct scsi_rewind +{ + u_char op_code; + u_char immed:1; + u_char :4; + u_char lun:3; + u_char unused[3]; + u_char link:1; + u_char flag:1; + u_char :6; +} rewind; + +struct scsi_load +{ + u_char op_code; + u_char immed:1; + u_char :4; + u_char lun:3; + u_char unused[2]; + u_char load:1; + u_char reten:1; + u_char :6; + u_char link:1; + u_char flag:1; + u_char :6; +} load; +#define LD_UNLOAD 0 +#define LD_LOAD 1 + +struct scsi_blk_limits +{ + u_char op_code; + u_char :5; + u_char lun:3; + u_char unused[3]; + u_char link:1; + u_char flag:1; + u_char :6; +} blk_limits; + +/* + * Opcodes + */ + +#define REWIND 0x01 +#define READ_BLK_LIMITS 0x05 +#define READ_COMMAND_TAPE 0x08 +#define WRITE_COMMAND_TAPE 0x0a +#define WRITE_FILEMARKS 0x10 +#define SPACE 0x11 +#define LOAD_UNLOAD 0x1b /* same as above */ + + + +struct scsi_blk_limits_data +{ + u_char reserved; + u_char max_length_2; /* Most significant */ + u_char max_length_1; + u_char max_length_0; /* Least significant */ + u_char min_length_1; /* Most significant */ + u_char min_length_0; /* Least significant */ +}; + +struct scsi_mode_header_tape +{ + u_char data_length; /* Sense data length */ + u_char medium_type; + u_char speed:4; + u_char buf_mode:3; + u_char write_protected:1; + u_char blk_desc_len; +}; + + +#define QIC_120 0x0f +#define QIC_150 0x10 +#define QIC_320 0x11 +#define QIC_525 0x11 +#define QIC_1320 0x12 + + diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c new file mode 100644 index 000000000000..fc1b5ca5f4b0 --- /dev/null +++ b/sys/scsi/scsiconf.c @@ -0,0 +1,761 @@ +/* + * Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 2 00149 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * 23 May 93 Rodney W. Grimes ADDED Pioneer DRM-600 cd changer + */ + +/* + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + */ + +/* +$Log: +* +*/ +#include <sys/types.h> +#include "st.h" +#include "sd.h" +#include "ch.h" +#include "cd.h" + +#ifdef MACH +#include <i386/machparam.h> +#endif MACH +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> + +#if !defined(OSF) && !defined(__386BSD__) +#include "bll.h" +#include "cals.h" +#include "kil.h" +#else +#define NBLL 0 +#define NCALS 0 +#define NKIL 0 +#endif /* !defined(OSF) && !defined(__386BSD__) */ + +#if NSD > 0 +extern sdattach(); +#endif NSD +#if NST > 0 +extern stattach(); +#endif NST +#if NCH > 0 +extern chattach(); +#endif NCH +#if NCD > 0 +extern cdattach(); +#endif NCD +#if NBLL > 0 +extern bllattach(); +#endif NBLL +#if NCALS > 0 +extern calsattach(); +#endif NCALS +#if NKIL > 0 +extern kil_attach(); +#endif NKIL + +/***************************************************************\ +* The structure of pre-configured devices that might be turned * +* off and therefore may not show up * +\***************************************************************/ +struct predefined +{ + u_char scsibus; + u_char dev; + u_char lu; + int (*attach_rtn)(); + char *devname; + char flags; +} +pd[] = +{ +#ifdef EXAMPLE_PREDEFINE +#if NSD > 0 + {0,0,0,sdattach,"sd",0},/* define a disk at scsibus=0 dev=0 lu=0 */ +#endif NSD +#endif EXAMPLE_PREDEFINE + {0,9,9} /*illegal dummy end entry */ +}; + + +/***************************************************************\ +* The structure of known drivers for autoconfiguration * +\***************************************************************/ +static struct scsidevs +{ + int type; + int removable; + char *manufacturer; + char *model; + char *version; + int (*attach_rtn)(); + char *devname; + char flags; /* 1 show my comparisons during boot(debug) */ +} +#define SC_SHOWME 0x01 +#define SC_ONE_LU 0x00 +#define SC_MORE_LUS 0x02 +knowndevs[] = { +#if NSD > 0 + { T_DIRECT,T_FIXED,"standard","any" + ,"any",sdattach,"sd",SC_ONE_LU }, + { T_DIRECT,T_FIXED,"MAXTOR ","XT-4170S " + ,"B5A ",sdattach,"mx1",SC_ONE_LU }, +#endif NSD +#if NST > 0 + { T_SEQUENTIAL,T_REMOV,"standard","any" + ,"any",stattach,"st",SC_ONE_LU }, +#endif NST +#if NCALS > 0 + { T_PROCESSOR,T_FIXED,"standard","any" + ,"any",calsattach,"cals",SC_MORE_LUS }, +#endif NCALS +#if NCH > 0 + { T_CHANGER,T_REMOV,"standard","any" + ,"any",chattach,"ch",SC_ONE_LU }, +#endif NCH +#if NCD > 0 + { T_READONLY,T_REMOV,"SONY ","CD-ROM CDU-8012 " + ,"3.1a",cdattach,"cd",SC_ONE_LU }, + { T_READONLY,T_REMOV,"PIONEER ","CD-ROM DRM-600 " + ,"any",cdattach,"cd",SC_MORE_LUS }, +#endif NCD +#if NBLL > 0 + { T_PROCESSOR,T_FIXED,"AEG ","READER " + ,"V1.0",bllattach,"bll",SC_MORE_LUS }, +#endif NBLL +#if NKIL > 0 + { T_SCANNER,T_FIXED,"KODAK ","IL Scanner 900 " + ,"any",kil_attach,"kil",SC_ONE_LU }, +#endif NKIL + +{0} +}; +/***************************************************************\ +* Declarations * +\***************************************************************/ +struct predefined *scsi_get_predef(); +struct scsidevs *scsi_probedev(); +struct scsidevs *selectdev(); + +/* controls debug level within the scsi subsystem */ +/* see scsiconf.h for values */ +int scsi_debug = 0x0; +int scsibus = 0x0; /* This is the Nth scsibus */ + +/***************************************************************\ +* The routine called by the adapter boards to get all their * +* devices configured in. * +\***************************************************************/ +scsi_attachdevs( unit, scsi_addr, scsi_switch) +int unit,scsi_addr; +struct scsi_switch *scsi_switch; +{ + int targ,lun; + struct scsidevs *bestmatch = (struct scsidevs *)0; + struct predefined *predef; + int maybe_more; + +#ifdef SCSI_DELAY +#if SCSI_DELAY > 2 + printf("waiting for scsi devices to settle\n"); +#else SCSI_DELAY > 2 +#define SCSI_DELAY 15 +#endif SCSI_DELAY > 2 +#else +#define SCSI_DELAY 2 +#endif SCSI_DELAY + spinwait(1000 * SCSI_DELAY); + targ = 0; + while(targ < 8) + { + maybe_more = 0; /* by default only check 1 lun */ + if (targ == scsi_addr) + { + targ++; + continue; + } + lun = 0; + while(lun < 8) + { + predef = scsi_get_predef(scsibus + ,targ + ,lun + ,&maybe_more); + bestmatch = scsi_probedev(unit + ,targ + ,lun + ,scsi_switch + ,&maybe_more); + if((bestmatch) && (predef)) /* both exist */ + { + if(bestmatch->attach_rtn + != predef->attach_rtn) + { + printf("Clash in found/expected devices\n"); + printf("will link in FOUND\n"); + } + (*(bestmatch->attach_rtn))(unit, + targ, + lun, + scsi_switch); + } + if((bestmatch) && (!predef)) /* just FOUND */ + { + (*(bestmatch->attach_rtn))(unit, + targ, + lun, + scsi_switch); + } + if((!bestmatch) && (predef)) /* just predef */ + { + (*(predef->attach_rtn))(unit, + targ, + lun, + scsi_switch); + } + if(!(maybe_more)) /* nothing suggests we'll find more */ + { + break; /* nothing here, skip to next targ */ + } + /* otherwise something says we should look further*/ + lun++; + } + targ++; + } +#if NGENSCSI > 0 + /***************************************************************\ + * If available hook up the generic scsi driver, letting it * + * know which target is US. (i.e. illegal or at least special) * + \***************************************************************/ + genscsi_attach(unit,scsi_addr,0,scsi_switch); +#endif + scsibus++; /* next time we are on the NEXT scsi bus */ +} + +/***********************************************\ +* given a target and lu, check if there is a * +* predefined device for that address * +\***********************************************/ +struct predefined *scsi_get_predef(unit,target,lu,maybe_more) +int unit,target,lu,*maybe_more; +{ + int upto,numents; + + numents = (sizeof(pd)/sizeof(struct predefined)) - 1; + + for(upto = 0;upto < numents;upto++) + { + if(pd[upto].scsibus != unit) + continue; + if(pd[upto].dev != target) + continue; + if(pd[upto].lu != lu) + continue; + + printf(" dev%d,lu%d: %s - PRECONFIGURED -\n" + ,target + ,lu + ,pd[upto].devname); + *maybe_more = pd[upto].flags & SC_MORE_LUS; + return(&(pd[upto])); + } + return((struct predefined *)0); +} + +/***********************************************\ +* given a target and lu, ask the device what * +* it is, and find the correct driver table * +* entry. * +\***********************************************/ +struct scsidevs *scsi_probedev(unit,target,lu,scsi_switch, maybe_more) + +struct scsi_switch *scsi_switch; +int unit,target,lu; +int *maybe_more; +{ + struct scsidevs *bestmatch = (struct scsidevs *)0; + char *dtype=(char *)0,*desc; + char *qtype; + static struct scsi_inquiry_data inqbuf; + int len,qualifier,type,remov; + char manu[32]; + char model[32]; + char version[32]; + + + bzero(&inqbuf,sizeof(inqbuf)); + /***********************************************\ + * Ask the device what it is * + \***********************************************/ +#ifdef DEBUG + if((target == 0) && (lu == 0)) + scsi_debug = 0xfff; + else + scsi_debug = 0; +#endif DEBUG + if(scsi_ready( unit, + target, + lu, + scsi_switch, + SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE) + { + return(struct scsidevs *)0; + } + if(scsi_inquire(unit, + target, + lu, + scsi_switch, + &inqbuf, + SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE) + { + return(struct scsidevs *)0; + } + + /***********************************************\ + * note what BASIC type of device it is * + \***********************************************/ + if(scsi_debug & SHOWINQUIRY) + { + desc=(char *)&inqbuf; + printf("inq: %x %x %x %x %x %x %x %x %x %x %x %x %x\n", + desc[0], desc[1], desc[2], desc[3], + desc[4], desc[5], desc[6], desc[7], + desc[8], desc[9], desc[10], desc[11], + desc[12]); + } + + type = inqbuf.device_type; + qualifier = inqbuf.device_qualifier; + remov = inqbuf.removable; + + /* Check for a non-existent unit. If the device is returning + * this much, then we must set the flag that has + * the searcher keep looking on other luns. + */ + if (qualifier == 3 && type == T_NODEVICE) + { + *maybe_more = 1; + return (struct scsidevs *)0; + } + + /* Any device qualifier that has + * the top bit set (qualifier&4 != 0) is vendor specific and + * won't match in this switch. + */ + + switch(qualifier) + { + case 0: + qtype=""; + break; + case 1: + qtype=", Unit not Connected!"; + break; + case 2: + qtype=", Reserved Peripheral Qualifier!"; + break; + case 3: + qtype=", The Target can't support this Unit!"; + break; + + default: + dtype="vendor specific"; + qtype=""; + *maybe_more = 1; + break; + } + + if (dtype == 0) + switch(type) + { + case T_DIRECT: + dtype="direct"; + break; + case T_SEQUENTIAL: + dtype="sequential"; + break; + case T_PRINTER: + dtype="printer"; + break; + case T_PROCESSOR: + dtype="processor"; + break; + case T_READONLY: + dtype="readonly"; + break; + case T_WORM: + dtype="worm"; + break; + case T_SCANNER: + dtype="scanner"; + break; + case T_OPTICAL: + dtype="optical"; + break; + case T_CHANGER: + dtype="changer"; + break; + case T_COMM: + dtype="communication"; + break; + default: + dtype="unknown"; + break; + } + + /***********************************************\ + * Then if it's advanced enough, more detailed * + * information * + \***********************************************/ + if(inqbuf.ansii_version > 0) + { + if ((len = inqbuf.additional_length + + ( (char *)inqbuf.unused + - (char *)&inqbuf)) + > (sizeof(struct scsi_inquiry_data) - 1)) + len = sizeof(struct scsi_inquiry_data) - 1; + desc=inqbuf.vendor; + desc[len-(desc - (char *)&inqbuf)] = 0; + strncpy(manu,inqbuf.vendor,8);manu[8]=0; + strncpy(model,inqbuf.product,16);model[16]=0; + strncpy(version,inqbuf.revision,4);version[4]=0; + } + else + /***********************************************\ + * If not advanced enough, use default values * + \***********************************************/ + { + desc="early protocol device"; + strncpy(manu,"unknown",8); + strncpy(model,"unknown",16); + strncpy(version,"????",4); + } + printf(" dev%d,lu%d: type %d:%d(%s%s),%s '%s%s%s' scsi%d\n" + ,target + ,lu + ,qualifier,type + ,dtype,qtype + ,remov?"removable":"fixed" + ,manu + ,model + ,version + ,inqbuf.ansii_version + ); + /***********************************************\ + * Try make as good a match as possible with * + * available sub drivers * + \***********************************************/ + bestmatch = (selectdev(unit,target,lu,&scsi_switch, + qualifier,type,remov,manu,model,version)); + if((bestmatch) && (bestmatch->flags & SC_MORE_LUS)) + { + *maybe_more = 1; + } + return(bestmatch); +} + +/***********************************************\ +* Try make as good a match as possible with * +* available sub drivers * +\***********************************************/ +struct scsidevs +*selectdev(unit,target,lu,dvr_switch,qualifier,type,remov,manu,model,rev) +int unit,target,lu; +struct scsi_switch *dvr_switch; +int qualifier,type,remov; +char *manu,*model,*rev; +{ + int numents = (sizeof(knowndevs)/sizeof(struct scsidevs)) - 1; + int count = 0; + int bestmatches = 0; + struct scsidevs *bestmatch = (struct scsidevs *)0; + struct scsidevs *thisentry = knowndevs; + + type |= (qualifier << 5); + + thisentry--; + while( count++ < numents) + { + thisentry++; + if(type != thisentry->type) + { + continue; + } + if(bestmatches < 1) + { + bestmatches = 1; + bestmatch = thisentry; + } + if(remov != thisentry->removable) + { + continue; + } + if(bestmatches < 2) + { + bestmatches = 2; + bestmatch = thisentry; + } + if(thisentry->flags & SC_SHOWME) + printf("\n%s-\n%s-",thisentry->manufacturer, manu); + if(strcmp(thisentry->manufacturer, manu)) + { + continue; + } + if(bestmatches < 3) + { + bestmatches = 3; + bestmatch = thisentry; + } + if(thisentry->flags & SC_SHOWME) + printf("\n%s-\n%s-",thisentry->model, model); + if(strcmp(thisentry->model, model)) + { + continue; + } + if(bestmatches < 4) + { + bestmatches = 4; + bestmatch = thisentry; + } + if(thisentry->flags & SC_SHOWME) + printf("\n%s-\n%s-",thisentry->version, rev); + if(strcmp(thisentry->version, rev)) + { + continue; + } + if(bestmatches < 5) + { + bestmatches = 5; + bestmatch = thisentry; + break; + } + } + + if (bestmatch == (struct scsidevs *)0) + printf(" No explicit device driver match for \"%s %s\".\n", + manu, model); + + return(bestmatch); +} + +static int recurse = 0; +/***********************************************\ +* Do a scsi operation asking a device if it is * +* ready. Use the scsi_cmd routine in the switch * +* table. * +\***********************************************/ +scsi_ready(unit,target,lu,scsi_switch, flags) +struct scsi_switch *scsi_switch; +{ + struct scsi_test_unit_ready scsi_cmd; + struct scsi_xfer scsi_xfer; + volatile int rval; + int key; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + bzero(&scsi_xfer, sizeof(scsi_xfer)); + scsi_cmd.op_code = TEST_UNIT_READY; + + scsi_xfer.flags=flags | INUSE; + scsi_xfer.adapter=unit; + scsi_xfer.targ=target; + scsi_xfer.lu=lu; + scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd; + scsi_xfer.retries=8; + scsi_xfer.timeout=10000; + scsi_xfer.cmdlen=sizeof(scsi_cmd); + scsi_xfer.data=0; + scsi_xfer.datalen=0; + scsi_xfer.resid=0; + scsi_xfer.when_done=0; + scsi_xfer.done_arg=0; +retry: scsi_xfer.error=0; + /*******************************************************\ + * do not use interrupts * + \*******************************************************/ + rval = (*(scsi_switch->scsi_cmd))(&scsi_xfer); + if (rval != COMPLETE) + { + if(scsi_debug) + { + printf("scsi error, rval = 0x%x\n",rval); + printf("code from driver: 0x%x\n",scsi_xfer.error); + } + switch(scsi_xfer.error) + { + case XS_SENSE: + /*******************************************************\ + * Any sense value is illegal except UNIT ATTENTION * + * In which case we need to check again to get the * + * correct response. * + *( especially exabytes) * + \*******************************************************/ + if(scsi_xfer.sense.error_class == 7 ) + { + key = scsi_xfer.sense.ext.extended.sense_key ; + switch(key) + { + case 2: /* not ready BUT PRESENT! */ + return(COMPLETE); + case 6: + spinwait(1000); + if(scsi_xfer.retries--) + { + scsi_xfer.flags &= ~ITSDONE; + goto retry; + } + return(COMPLETE); + default: + if(scsi_debug) + printf("%d:%d,key=%x.", + target,lu,key); + } + } + return(HAD_ERROR); + case XS_BUSY: + spinwait(1000); + if(scsi_xfer.retries--) + { + scsi_xfer.flags &= ~ITSDONE; + goto retry; + } + return(COMPLETE); /* it's busy so it's there */ + case XS_TIMEOUT: + default: + return(HAD_ERROR); + } + } + return(COMPLETE); +} +/***********************************************\ +* Do a scsi operation asking a device what it is* +* Use the scsi_cmd routine in the switch table. * +\***********************************************/ +scsi_inquire(unit,target,lu,scsi_switch,inqbuf, flags) +struct scsi_switch *scsi_switch; +u_char *inqbuf; +{ + struct scsi_inquiry scsi_cmd; + struct scsi_xfer scsi_xfer; + volatile int rval; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + bzero(&scsi_xfer, sizeof(scsi_xfer)); + scsi_cmd.op_code = INQUIRY; + scsi_cmd.length = sizeof(struct scsi_inquiry_data); + + scsi_xfer.flags=flags | SCSI_DATA_IN | INUSE; + scsi_xfer.adapter=unit; + scsi_xfer.targ=target; + scsi_xfer.lu=lu; + scsi_xfer.retries=8; + scsi_xfer.timeout=10000; + scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd; + scsi_xfer.cmdlen= sizeof(struct scsi_inquiry); + scsi_xfer.data=inqbuf; + scsi_xfer.datalen=sizeof(struct scsi_inquiry_data); + scsi_xfer.resid=sizeof(struct scsi_inquiry_data); + scsi_xfer.when_done=0; + scsi_xfer.done_arg=0; +retry: scsi_xfer.error=0; + /*******************************************************\ + * do not use interrupts * + \*******************************************************/ + if ((*(scsi_switch->scsi_cmd))(&scsi_xfer) != COMPLETE) + { + if(scsi_debug) printf("inquiry had error(0x%x) ",scsi_xfer.error); + switch(scsi_xfer.error) + { + case XS_NOERROR: + break; + case XS_SENSE: + /*******************************************************\ + * Any sense value is illegal except UNIT ATTENTION * + * In which case we need to check again to get the * + * correct response. * + *( especially exabytes) * + \*******************************************************/ + if((scsi_xfer.sense.error_class == 7 ) + && (scsi_xfer.sense.ext.extended.sense_key == 6)) + { /* it's changed so it's there */ + spinwait(1000); + { + if(scsi_xfer.retries--) + { + scsi_xfer.flags &= ~ITSDONE; + goto retry; + } + } + return( COMPLETE); + } + return(HAD_ERROR); + case XS_BUSY: + spinwait(1000); + if(scsi_xfer.retries--) + { + scsi_xfer.flags &= ~ITSDONE; + goto retry; + } + case XS_TIMEOUT: + default: + return(HAD_ERROR); + } + } + return(COMPLETE); +} + + + + +/***********************************************\ +* Utility routines often used in SCSI stuff * +\***********************************************/ + +/***********************************************\ +* convert a physical address to 3 bytes, * +* MSB at the lowest address, * +* LSB at the highest. * +\***********************************************/ + +lto3b(val, bytes) +u_char *bytes; +{ + *bytes++ = (val&0xff0000)>>16; + *bytes++ = (val&0xff00)>>8; + *bytes = val&0xff; +} + +/***********************************************\ +* The reverse of lto3b * +\***********************************************/ +_3btol(bytes) +u_char *bytes; +{ + int rc; + rc = (*bytes++ << 16); + rc += (*bytes++ << 8); + rc += *bytes; + return(rc); +} + diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h new file mode 100644 index 000000000000..c36efde535c8 --- /dev/null +++ b/sys/scsi/scsiconf.h @@ -0,0 +1,113 @@ +/* + * Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * + */ + +/* + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + */ + +/***********************************************\ +* these calls are called by the high-end * +* drivers to get services from whatever low-end * +* drivers they are attached to * +\***********************************************/ +struct scsi_switch +{ + int (*scsi_cmd)(); + void (*scsi_minphys)(); + int (*open_target_lu)(); + int (*close_target_lu)(); + long int (*adapter_info)(); /* see definitions below */ + u_long spare[3]; +}; +#define AD_INF_MAX_CMDS 0x000000FF /* maximum number of entries + queuable to a device by + the adapter */ +/* 24 bits of other adapter charcteristics go here */ + +/***********************************************\ +* The scsi debug control bits * +\***********************************************/ +extern int scsi_debug; +#define PRINTROUTINES 0x01 +#define TRACEOPENS 0x02 +#define TRACEINTERRUPTS 0x04 +#define SHOWREQUESTS 0x08 +#define SHOWSCATGATH 0x10 +#define SHOWINQUIRY 0x20 +#define SHOWCOMMANDS 0x40 + + +/********************************/ +/* return values for scsi_cmd() */ +/********************************/ +#define SUCCESSFULLY_QUEUED 0 +#define TRY_AGAIN_LATER 1 +#define COMPLETE 2 +#define HAD_ERROR 3 + +struct scsi_xfer +{ + struct scsi_xfer *next; /* when free */ + int flags; + u_char adapter; + u_char targ; + u_char lu; + u_char retries; /* the number of times to retry */ + long int timeout; /* in miliseconds */ + struct scsi_generic *cmd; + int cmdlen; + u_char *data; /* either the dma address OR a uio address */ + int datalen; /* data len (blank if uio) */ + int resid; + int (*when_done)(); + int done_arg; + int done_arg2; + int error; + struct buf *bp; + struct scsi_sense_data sense; +}; +/********************************/ +/* Flag values */ +/********************************/ +#define SCSI_NOSLEEP 0x01 /* Not a user... don't sleep */ +#define SCSI_NOMASK 0x02 /* dont allow interrupts.. booting */ +#define SCSI_NOSTART 0x04 /* left over from ancient history */ +#define ITSDONE 0x10 /* the transfer is as done as it gets */ +#define INUSE 0x20 /* The scsi_xfer block is in use */ +#define SCSI_SILENT 0x40 /* Don't report errors to console */ +#define SCSI_ERR_OK 0x80 /* An error on this operation is OK. */ +#define SCSI_RESET 0x100 /* Reset the device in question */ +#define SCSI_DATA_UIO 0x200 /* The data address refers to a UIO */ +#define SCSI_DATA_IN 0x400 /* expect data to come INTO memory */ +#define SCSI_DATA_OUT 0x800 /* expect data to flow OUT of memory */ +#define SCSI_TARGET 0x1000 /* This defines a TARGET mode op. */ +/********************************/ +/* Error values */ +/********************************/ +#define XS_NOERROR 0x0 /* there is no error, (sense is invalid) */ +#define XS_SENSE 0x1 /* Check the returned sense for the error */ +#define XS_DRIVER_STUFFUP 0x2 /* Driver failed to perform operation */ +#define XS_TIMEOUT 0x03 /* The device timed out.. turned off? */ +#define XS_SWTIMEOUT 0x04 /* The Timeout reported was caught by SW */ +#define XS_BUSY 0x08 /* The device busy, try again later? */ + diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c new file mode 100644 index 000000000000..af8ae7917667 --- /dev/null +++ b/sys/scsi/sd.c @@ -0,0 +1,1466 @@ +/* + * Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 2 00149 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * 20 Apr 93 Julian Elischer Fixed error reporting + * + */ + +static char rev[] = "$Revision: 1.3 $"; + +/* + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + */ + +#define SPLSD splbio +#define ESUCCESS 0 +#include <sd.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/dkbad.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/buf.h> +#include <sys/uio.h> +#include <sys/malloc.h> +#include <sys/errno.h> +#include <sys/disklabel.h> +#include <scsi/scsi_all.h> +#include <scsi/scsi_disk.h> +#include <scsi/scsiconf.h> + +long int sdstrats,sdqueues; + + +#include <ddb.h> +#if NDDB > 0 +int Debugger(); +#else NDDB > 0 +#define Debugger() +#endif NDDB > 0 + + +#define PAGESIZ 4096 +#define SECSIZE 512 +#define PDLOCATION 29 +#define BOOTRECORDSIGNATURE (0x55aa & 0x00ff) +#define SDOUTSTANDING 2 +#define SDQSIZE 4 +#define SD_RETRIES 4 + +#define MAKESDDEV(maj, unit, part) (makedev(maj,((unit<<3)+part))) +#define UNITSHIFT 3 +#define PARTITION(z) (minor(z) & 0x07) +#define RAW_PART 3 +#define UNIT(z) ( (minor(z) >> UNITSHIFT) ) + +#define WHOLE_DISK(unit) ( (unit << UNITSHIFT) + RAW_PART ) + +struct buf sd_buf_queue[NSD]; +int sd_done(); +int sdstrategy(); + +int sd_debug = 0; + +struct scsi_xfer *sd_free_xfer[NSD]; +int sd_xfer_block_wait[NSD]; + +struct sd_data +{ + int flags; +#define SDVALID 0x02 /* PARAMS LOADED */ +#define SDINIT 0x04 /* device has been init'd */ +#define SDWAIT 0x08 /* device has someone waiting */ +#define SDHAVELABEL 0x10 /* have read the label */ +#define SDDOSPART 0x20 /* Have read the DOS partition table */ +#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W)*/ + struct scsi_switch *sc_sw; /* address of scsi low level switch */ + int ctlr; /* so they know which one we want */ + int targ; /* our scsi target ID */ + int lu; /* out scsi lu */ + long int ad_info; /* info about the adapter */ + int cmdscount; /* cmds allowed outstanding by board*/ + int wlabel; /* label is writable */ + struct disk_parms + { + u_char heads; /* Number of heads */ + u_short cyls; /* Number of cylinders */ + u_char sectors;/*dubious*/ /* Number of sectors/track */ + u_short secsiz; /* Number of bytes/sector */ + u_long disksize; /* total number sectors */ + }params; + struct disklabel disklabel; + struct dos_partition dosparts[NDOSPART]; /* DOS view of disk */ + int partflags[MAXPARTITIONS]; /* per partition flags */ +#define SDOPEN 0x01 + int openparts; /* one bit for each open partition */ + unsigned int sd_start_of_unix; /* unix vs dos partitions */ +}sd_data[NSD]; + + +static int next_sd_unit = 0; +/***********************************************************************\ +* The routine called by the low level scsi routine when it discovers * +* A device suitable for this driver * +\***********************************************************************/ + +int sdattach(ctlr,targ,lu,scsi_switch) +struct scsi_switch *scsi_switch; +{ + int unit,i; + unsigned char *tbl; + struct sd_data *sd; + struct disk_parms *dp; + long int ad_info; + struct scsi_xfer *sd_scsi_xfer; + + unit = next_sd_unit++; + sd = sd_data + unit; + dp = &(sd->params); + if(scsi_debug & PRINTROUTINES) printf("sdattach: "); + /*******************************************************\ + * Check we have the resources for another drive * + \*******************************************************/ + if( unit >= NSD) + { + printf("Too many scsi disks..(%d > %d) reconfigure kernel",(unit + 1),NSD); + return(0); + } + /*******************************************************\ + * Store information needed to contact our base driver * + \*******************************************************/ + sd->sc_sw = scsi_switch; + sd->ctlr = ctlr; + sd->targ = targ; + sd->lu = lu; + if(sd->sc_sw->adapter_info) + { + sd->ad_info = ( (*(sd->sc_sw->adapter_info))(ctlr)); + sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS; + if(sd->cmdscount > SDOUTSTANDING) + { + sd->cmdscount = SDOUTSTANDING; + } + } + else + { + sd->ad_info = 1; + sd->cmdscount = 1; + } + + i = sd->cmdscount; + sd_scsi_xfer = (struct scsi_xfer *)malloc(sizeof(struct scsi_xfer) * i + ,M_TEMP, M_NOWAIT); + while(i-- ) + { + sd_scsi_xfer->next = sd_free_xfer[unit]; + sd_free_xfer[unit] = sd_scsi_xfer; + sd_scsi_xfer++; + } + /*******************************************************\ + * Use the subdriver to request information regarding * + * the drive. We cannot use interrupts yet, so the * + * request must specify this. * + \*******************************************************/ + sd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK); + printf(" sd%d: %dMB, cyls %d, heads %d, secs %d, bytes/sec %d\n", + unit, + ( dp->cyls + * dp->heads + * dp->sectors + * dp->secsiz + ) + / (1024 * 1024), + dp->cyls, + dp->heads, + dp->sectors, + dp->secsiz); + /*******************************************************\ + * Set up the bufs for this device * + \*******************************************************/ + sd->flags |= SDINIT; + return; + +} + + + +/*******************************************************\ +* open the device. Make sure the partition info * +* is a up-to-date as can be. * +\*******************************************************/ +sdopen(dev) +{ + int errcode = 0; + int unit, part; + struct disk_parms disk_parms; + struct sd_data *sd ; + + unit = UNIT(dev); + part = PARTITION(dev); + sd = sd_data + unit; + if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) + printf("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n" + , dev, unit, NSD, part); + /*******************************************************\ + * Check the unit is legal * + \*******************************************************/ + if ( unit >= NSD ) + { + return(ENXIO); + } + /*******************************************************\ + * Make sure the disk has been initialised * + * At some point in the future, get the scsi driver * + * to look for a new device if we are not initted * + \*******************************************************/ + if (! (sd->flags & SDINIT)) + { + return(ENXIO); + } + + /*******************************************************\ + * If it's been invalidated, and not everybody has * + * closed it then forbid re-entry. * + \*******************************************************/ + if ((! (sd->flags & SDVALID)) + && ( sd->openparts)) + return(ENXIO); + /*******************************************************\ + * Check that it is still responding and ok. * + * "unit attention errors should occur here if the drive * + * has been restarted or the pack changed * + \*******************************************************/ + + if(scsi_debug & TRACEOPENS) + printf("device is "); + if (sd_test_unit_ready(unit,0)) + { + if(scsi_debug & TRACEOPENS) printf("not reponding\n"); + return(ENXIO); + } + if(scsi_debug & TRACEOPENS) + printf("ok\n"); + /*******************************************************\ + * In case it is a funny one, tell it to start * + * not needed for most hard drives (ignore failure) * + \*******************************************************/ + sd_start_unit(unit,SCSI_ERR_OK|SCSI_SILENT); + if(scsi_debug & TRACEOPENS) + printf("started "); + /*******************************************************\ + * Load the physical device parameters * + \*******************************************************/ + sd_get_parms(unit, 0); /* sets SDVALID */ + if (sd->params.secsiz != SECSIZE) + { + printf("sd%d: Can't deal with %d bytes logical blocks\n" + ,unit, sd->params.secsiz); + Debugger(); + return(ENXIO); + } + if(scsi_debug & TRACEOPENS) + printf("Params loaded "); + /*******************************************************\ + * Load the partition info if not already loaded * + \*******************************************************/ + sd_prevent(unit,PR_PREVENT,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ + if((errcode = sdgetdisklabel(unit)) && (part != RAW_PART)) + { + sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ + return(errcode); + } + if(scsi_debug & TRACEOPENS) + printf("Disklabel loaded "); + /*******************************************************\ + * Check the partition is legal * + \*******************************************************/ + if ( part >= MAXPARTITIONS ) { + sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ + return(ENXIO); + } + if(scsi_debug & TRACEOPENS) + printf("ok"); + /*******************************************************\ + * Check that the partition exists * + \*******************************************************/ + if (( sd->disklabel.d_partitions[part].p_size == 0 ) + && (part != RAW_PART)) + { + sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ + return(ENXIO); + } + sd->partflags[part] |= SDOPEN; + sd->openparts |= (1 << part); + if(scsi_debug & TRACEOPENS) + printf("open %d %d\n",sdstrats,sdqueues); + return(0); +} + +/*******************************************************\ +* Get ownership of a scsi_xfer * +* If need be, sleep on it, until it comes free * +\*******************************************************/ +struct scsi_xfer *sd_get_xs(unit,flags) +int flags; +int unit; +{ + struct scsi_xfer *xs; + int s; + + if(flags & (SCSI_NOSLEEP | SCSI_NOMASK)) + { + if (xs = sd_free_xfer[unit]) + { + sd_free_xfer[unit] = xs->next; + xs->flags = 0; + } + } + else + { + s = SPLSD(); + while (!(xs = sd_free_xfer[unit])) + { + sd_xfer_block_wait[unit]++; /* someone waiting! */ + sleep((caddr_t)&sd_free_xfer[unit], PRIBIO+1); + sd_xfer_block_wait[unit]--; + } + sd_free_xfer[unit] = xs->next; + splx(s); + xs->flags = 0; + } + return(xs); +} + +/*******************************************************\ +* Free a scsi_xfer, wake processes waiting for it * +\*******************************************************/ +sd_free_xs(unit,xs,flags) +struct scsi_xfer *xs; +int unit; +int flags; +{ + int s; + + if(flags & SCSI_NOMASK) + { + if (sd_xfer_block_wait[unit]) + { + printf("doing a wakeup from NOMASK mode\n"); + wakeup((caddr_t)&sd_free_xfer[unit]); + } + xs->next = sd_free_xfer[unit]; + sd_free_xfer[unit] = xs; + } + else + { + s = SPLSD(); + if (sd_xfer_block_wait[unit]) + wakeup((caddr_t)&sd_free_xfer[unit]); + xs->next = sd_free_xfer[unit]; + sd_free_xfer[unit] = xs; + splx(s); + } +} + +/*******************************************************\ +* trim the size of the transfer if needed, * +* called by physio * +* basically the smaller of our max and the scsi driver's* +* minphys (note we have no max) * +\*******************************************************/ +/* Trim buffer length if buffer-size is bigger than page size */ +void sdminphys(bp) +struct buf *bp; +{ + (*(sd_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp); +} + +/*******************************************************\ +* Actually translate the requested transfer into * +* one the physical driver can understand * +* The transfer is described by a buf and will include * +* only one physical transfer. * +\*******************************************************/ + +int sdstrategy(bp) +struct buf *bp; +{ + struct buf *dp; + unsigned int opri; + struct sd_data *sd ; + int unit; + + sdstrats++; + unit = UNIT((bp->b_dev)); + sd = sd_data + unit; + if(scsi_debug & PRINTROUTINES) printf("\nsdstrategy "); + if(scsi_debug & SHOWREQUESTS) printf("sd%d: %d bytes @ blk%d\n", + unit,bp->b_bcount,bp->b_blkno); + sdminphys(bp); + /*******************************************************\ + * If the device has been made invalid, error out * + \*******************************************************/ + if(!(sd->flags & SDVALID)) + { + bp->b_error = EIO; + goto bad; + } + /*******************************************************\ + * "soft" write protect check * + \*******************************************************/ + if ((sd->flags & SDWRITEPROT) && (bp->b_flags & B_READ) == 0) { + bp->b_error = EROFS; + goto bad; + } + /*******************************************************\ + * If it's a null transfer, return immediatly * + \*******************************************************/ + if (bp->b_bcount == 0) + { + goto done; + } + + /*******************************************************\ + * Decide which unit and partition we are talking about * + * only raw is ok if no label * + \*******************************************************/ + if(PARTITION(bp->b_dev) != RAW_PART) + { + if (!(sd->flags & SDHAVELABEL)) + { + bp->b_error = EIO; + goto bad; + } + + /* + * do bounds checking, adjust transfer. if error, process. + * if end of partition, just return + */ + if (bounds_check_with_label(bp,&sd->disklabel,sd->wlabel) <= 0) + goto done; + /* otherwise, process transfer request */ + } + + opri = SPLSD(); + dp = &sd_buf_queue[unit]; + + /*******************************************************\ + * Place it in the queue of disk activities for this disk* + \*******************************************************/ + disksort(dp, bp); + + /*******************************************************\ + * Tell the device to get going on the transfer if it's * + * not doing anything, otherwise just wait for completion* + \*******************************************************/ + sdstart(unit); + + splx(opri); + return; +bad: + bp->b_flags |= B_ERROR; +done: + + /*******************************************************\ + * Correctly set the buf to indicate a completed xfer * + \*******************************************************/ + bp->b_resid = bp->b_bcount; + biodone(bp); + return; +} + +/***************************************************************\ +* sdstart looks to see if there is a buf waiting for the device * +* and that the device is not already busy. If both are true, * +* It deques the buf and creates a scsi command to perform the * +* transfer in the buf. The transfer request will call sd_done * +* on completion, which will in turn call this routine again * +* so that the next queued transfer is performed. * +* The bufs are queued by the strategy routine (sdstrategy) * +* * +* This routine is also called after other non-queued requests * +* have been made of the scsi driver, to ensure that the queue * +* continues to be drained. * +* * +* must be called at the correct (highish) spl level * +\***************************************************************/ +/* sdstart() is called at SPLSD from sdstrategy and sd_done*/ +sdstart(unit) +int unit; +{ + int drivecount; + register struct buf *bp = 0; + register struct buf *dp; + struct scsi_xfer *xs; + struct scsi_rw_big cmd; + int blkno, nblk; + struct sd_data *sd = sd_data + unit; + struct partition *p ; + + if(scsi_debug & PRINTROUTINES) printf("sdstart%d ",unit); + /*******************************************************\ + * See if there is a buf to do and we are not already * + * doing one * + \*******************************************************/ + if(!sd_free_xfer[unit]) + { + return; /* none for us, unit already underway */ + } + + if(sd_xfer_block_wait[unit]) /* there is one, but a special waits */ + { + return; /* give the special that's waiting a chance to run */ + } + + + dp = &sd_buf_queue[unit]; + if ((bp = dp->b_actf) != NULL) /* yes, an assign */ + { + dp->b_actf = bp->av_forw; + } + else + { + return; + } + + xs=sd_get_xs(unit,0); /* ok we can grab it */ + xs->flags = INUSE; /* Now ours */ + /*******************************************************\ + * If the device has become invalid, abort all the * + * reads and writes until all files have been closed and * + * re-openned * + \*******************************************************/ + if(!(sd->flags & SDVALID)) + { + xs->error = XS_DRIVER_STUFFUP; + sd_done(unit,xs); /* clean up (calls sdstart) */ + return ; + } + /*******************************************************\ + * We have a buf, now we should move the data into * + * a scsi_xfer definition and try start it * + \*******************************************************/ + /*******************************************************\ + * First, translate the block to absolute * + \*******************************************************/ + p = sd->disklabel.d_partitions + PARTITION(bp->b_dev); + blkno = bp->b_blkno + p->p_offset; + nblk = (bp->b_bcount + 511) >> 9; + + /*******************************************************\ + * Fill out the scsi command * + \*******************************************************/ + bzero(&cmd, sizeof(cmd)); + cmd.op_code = (bp->b_flags & B_READ) + ? READ_BIG : WRITE_BIG; + cmd.addr_3 = (blkno & 0xff000000) >> 24; + cmd.addr_2 = (blkno & 0xff0000) >> 16; + cmd.addr_1 = (blkno & 0xff00) >> 8; + cmd.addr_0 = blkno & 0xff; + cmd.length2 = (nblk & 0xff00) >> 8; + cmd.length1 = (nblk & 0xff); + /*******************************************************\ + * Fill out the scsi_xfer structure * + * Note: we cannot sleep as we may be an interrupt * + \*******************************************************/ + xs->flags |= SCSI_NOSLEEP; + xs->adapter = sd->ctlr; + xs->targ = sd->targ; + xs->lu = sd->lu; + xs->retries = SD_RETRIES; + xs->timeout = 10000;/* 10000 millisecs for a disk !*/ + xs->cmd = (struct scsi_generic *)&cmd; + xs->cmdlen = sizeof(cmd); + xs->resid = bp->b_bcount; + xs->when_done = sd_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; + xs->error = XS_NOERROR; + xs->bp = bp; + xs->data = (u_char *)bp->b_un.b_addr; + xs->datalen = bp->b_bcount; + /*******************************************************\ + * Pass all this info to the scsi driver. * + \*******************************************************/ + + + + if ( (*(sd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED) + { + printf("sd%d: oops not queued",unit); + xs->error = XS_DRIVER_STUFFUP; + sd_done(unit,xs); /* clean up (calls sdstart) */ + } + sdqueues++; +} + +/*******************************************************\ +* This routine is called by the scsi interrupt when * +* the transfer is complete. +\*******************************************************/ +int sd_done(unit,xs) +int unit; +struct scsi_xfer *xs; +{ + struct buf *bp; + int retval; + int retries = 0; + + if(scsi_debug & PRINTROUTINES) printf("sd_done%d ",unit); + if (! (xs->flags & INUSE)) + panic("scsi_xfer not in use!"); + if(bp = xs->bp) + { + switch(xs->error) + { + case XS_NOERROR: + bp->b_error = 0; + bp->b_resid = 0; + break; + + case XS_SENSE: + retval = (sd_interpret_sense(unit,xs)); + if(retval) + { + bp->b_flags |= B_ERROR; + bp->b_error = retval; + } + break; + + case XS_TIMEOUT: + printf("sd%d timeout\n",unit); + + case XS_BUSY: /* should retry */ /* how? */ + /************************************************/ + /* SHOULD put buf back at head of queue */ + /* and decrement retry count in (*xs) */ + /* HOWEVER, this should work as a kludge */ + /************************************************/ + if(xs->retries--) + { + xs->error = XS_NOERROR; + xs->flags &= ~ITSDONE; + if ( (*(sd_data[unit].sc_sw->scsi_cmd))(xs) + == SUCCESSFULLY_QUEUED) + { /* don't wake the job, ok? */ + return; + } + xs->flags |= ITSDONE; + } /* fall through */ + + case XS_DRIVER_STUFFUP: + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + break; + default: + printf("sd%d: unknown error category from scsi driver\n" + ,unit); + } + biodone(bp); + sd_free_xs(unit,xs,0); + sdstart(unit); /* If there's anything waiting.. do it */ + } + else /* special has finished */ + { + wakeup(xs); + } +} +/*******************************************************\ +* Perform special action on behalf of the user * +* Knows about the internals of this device * +\*******************************************************/ +sdioctl(dev_t dev, int cmd, caddr_t addr, int flag) +{ + /* struct sd_cmd_buf *args;*/ + int error = 0; + unsigned int opri; + unsigned char unit, part; + register struct sd_data *sd; + + + /*******************************************************\ + * Find the device that the user is talking about * + \*******************************************************/ + unit = UNIT(dev); + part = PARTITION(dev); + sd = &sd_data[unit]; + if(scsi_debug & PRINTROUTINES) printf("sdioctl%d ",unit); + + /*******************************************************\ + * If the device is not valid.. abandon ship * + \*******************************************************/ + if (!(sd_data[unit].flags & SDVALID)) + return(EIO); + switch(cmd) + { + + case DIOCSBAD: + error = EINVAL; + break; + + case DIOCGDINFO: + *(struct disklabel *)addr = sd->disklabel; + break; + + case DIOCGPART: + ((struct partinfo *)addr)->disklab = &sd->disklabel; + ((struct partinfo *)addr)->part = + &sd->disklabel.d_partitions[PARTITION(dev)]; + break; + + case DIOCSDINFO: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = setdisklabel(&sd->disklabel, + (struct disklabel *)addr, + /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */0, + sd->dosparts); + if (error == 0) { + sd->flags |= SDHAVELABEL; + } + break; + + case DIOCWLABEL: + sd->flags &= ~SDWRITEPROT; + if ((flag & FWRITE) == 0) + error = EBADF; + else + sd->wlabel = *(int *)addr; + break; + + case DIOCWDINFO: + sd->flags &= ~SDWRITEPROT; + if ((flag & FWRITE) == 0) + error = EBADF; + else + { + if ((error = setdisklabel(&sd->disklabel + , (struct disklabel *)addr + , /*(sd->flags & SDHAVELABEL) ? sd->openparts :*/ 0 + , sd->dosparts)) == 0) + { + int wlab; + + sd->flags |= SDHAVELABEL; /* ok write will succeed */ + + /* simulate opening partition 0 so write succeeds */ + sd->openparts |= (1 << 0); /* XXX */ + wlab = sd->wlabel; + sd->wlabel = 1; + error = writedisklabel(dev, sdstrategy, + &sd->disklabel, sd->dosparts); + sd->wlabel = wlab; + } + } + break; + + + default: + error = ENOTTY; + break; + } + return (error); +} + + +/*******************************************************\ +* Load the label information on the named device * +\*******************************************************/ +int sdgetdisklabel(unit) +unsigned char unit; +{ + /*unsigned int n, m;*/ + char *errstring; + struct dos_partition *dos_partition_p; + struct sd_data *sd = sd_data + unit; + + /*******************************************************\ + * If the inflo is already loaded, use it * + \*******************************************************/ + if(sd->flags & SDHAVELABEL) return(ESUCCESS); + + bzero(&sd->disklabel,sizeof(struct disklabel)); + /*******************************************************\ + * make partition 3 the whole disk in case of failure * + * then get pdinfo * + \*******************************************************/ + sd->disklabel.d_partitions[0].p_offset = 0; + sd->disklabel.d_partitions[0].p_size = sd->params.disksize; + sd->disklabel.d_partitions[RAW_PART].p_offset = 0; + sd->disklabel.d_partitions[RAW_PART].p_size = sd->params.disksize; + sd->disklabel.d_npartitions = MAXPARTITIONS; + sd->disklabel.d_secsize = 512; /* as long as it's not 0 */ + sd->disklabel.d_ntracks = sd->params.heads; + sd->disklabel.d_nsectors = sd->params.sectors; + sd->disklabel.d_ncylinders = sd->params.cyls; + sd->disklabel.d_secpercyl = sd->params.heads * sd->params.sectors; + if (sd->disklabel.d_secpercyl == 0) + { + sd->disklabel.d_secpercyl = 100; + /* as long as it's not 0 */ + /* readdisklabel divides by it */ + } + + /*******************************************************\ + * all the generic bisklabel extraction routine * + \*******************************************************/ + if(errstring = readdisklabel(makedev(0 ,(unit<<UNITSHIFT )+3) + , sdstrategy + , &sd->disklabel + , sd->dosparts + , 0 + , 0)) + { + printf("sd%d: %s\n",unit, errstring); + return(ENXIO); + } + /*******************************************************\ + * leave partition 2 "open" for raw I/O * + \*******************************************************/ + + sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */ + return(ESUCCESS); +} + +/*******************************************************\ +* Find out from the device what it's capacity is * +\*******************************************************/ +sd_size(unit, flags) +{ + struct scsi_read_cap_data rdcap; + struct scsi_read_capacity scsi_cmd; + int size; + + /*******************************************************\ + * make up a scsi command and ask the scsi driver to do * + * it for you. * + \*******************************************************/ + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = READ_CAPACITY; + + /*******************************************************\ + * If the command works, interpret the result as a 4 byte* + * number of blocks * + \*******************************************************/ + if (sd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + &rdcap, + sizeof(rdcap), + 2000, + flags) != 0) + { + printf("could not get size of unit %d\n", unit); + return(0); + } else { + size = rdcap.addr_0 + 1 ; + size += rdcap.addr_1 << 8; + size += rdcap.addr_2 << 16; + size += rdcap.addr_3 << 24; + } + return(size); +} + +/*******************************************************\ +* Get scsi driver to send a "are you ready?" command * +\*******************************************************/ +sd_test_unit_ready(unit,flags) +int unit,flags; +{ + struct scsi_test_unit_ready scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = TEST_UNIT_READY; + + return (sd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 100000, + flags)); +} + +/*******************************************************\ +* Prevent or allow the user to remove the tape * +\*******************************************************/ +sd_prevent(unit,type,flags) +int unit,type,flags; +{ + struct scsi_prevent scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = PREVENT_ALLOW; + scsi_cmd.prevent=type; + return (sd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 5000, + flags) ); +} +/*******************************************************\ +* Get scsi driver to send a "start up" command * +\*******************************************************/ +sd_start_unit(unit,flags) +int unit,flags; +{ + struct scsi_start_stop scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = START_STOP; + scsi_cmd.start = 1; + + return (sd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 2000, + flags)); +} + +/*******************************************************\ +* Tell the device to map out a defective block * +\*******************************************************/ +sd_reassign_blocks(unit,block) +{ + struct scsi_reassign_blocks scsi_cmd; + struct scsi_reassign_blocks_data rbdata; + + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + bzero(&rbdata, sizeof(rbdata)); + scsi_cmd.op_code = REASSIGN_BLOCKS; + + rbdata.length_msb = 0; + rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]); + rbdata.defect_descriptor[0].dlbaddr_3 = ((block >> 24) & 0xff); + rbdata.defect_descriptor[0].dlbaddr_2 = ((block >> 16) & 0xff); + rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff); + rbdata.defect_descriptor[0].dlbaddr_0 = ((block ) & 0xff); + + return(sd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + &rbdata, + sizeof(rbdata), + 5000, + 0)); +} + +#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) + +/*******************************************************\ +* Get the scsi driver to send a full inquiry to the * +* device and use the results to fill out the disk * +* parameter structure. * +\*******************************************************/ + +int sd_get_parms(unit, flags) +{ + struct sd_data *sd = sd_data + unit; + struct disk_parms *disk_parms = &sd->params; + struct scsi_mode_sense scsi_cmd; + struct scsi_mode_sense_data + { + struct scsi_mode_header header; + struct blk_desc blk_desc; + union disk_pages pages; + }scsi_sense; + int sectors; + + /*******************************************************\ + * First check if we have it all loaded * + \*******************************************************/ + if(sd->flags & SDVALID) return(0); + /*******************************************************\ + * First do a mode sense page 3 * + \*******************************************************/ + if (sd_debug) + { + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = MODE_SENSE; + scsi_cmd.page_code = 3; + scsi_cmd.length = 0x24; + /*******************************************************\ + * do the command, but we don't need the results * + * just print them for our interest's sake * + \*******************************************************/ + if (sd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + &scsi_sense, + sizeof(scsi_sense), + 2000, + flags) != 0) + { + printf("could not mode sense (3) for unit %d\n", unit); + return(ENXIO); + } + printf("unit %d: %d trk/zone, %d alt_sec/zone, %d alt_trk/zone, %d alt_trk/lun\n", + unit, + b2tol(scsi_sense.pages.disk_format.trk_z), + b2tol(scsi_sense.pages.disk_format.alt_sec), + b2tol(scsi_sense.pages.disk_format.alt_trk_z), + b2tol(scsi_sense.pages.disk_format.alt_trk_v)); + printf(" %d sec/trk, %d bytes/sec, %d interleave, %d %d bytes/log_blk\n", + b2tol(scsi_sense.pages.disk_format.ph_sec_t), + b2tol(scsi_sense.pages.disk_format.bytes_s), + b2tol(scsi_sense.pages.disk_format.interleave), + sd_size(unit, flags), + _3btol(scsi_sense.blk_desc.blklen)); + } + + + /*******************************************************\ + * do a "mode sense page 4" * + \*******************************************************/ + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = MODE_SENSE; + scsi_cmd.page_code = 4; + scsi_cmd.length = 0x20; + /*******************************************************\ + * If the command worked, use the results to fill out * + * the parameter structure * + \*******************************************************/ + if (sd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + &scsi_sense, + sizeof(scsi_sense), + 2000, + flags) != 0) + { + printf("could not mode sense (4) for unit %d\n", unit); + printf(" using ficticious geometry\n"); + /* use adaptec standard ficticious geometry */ + sectors = sd_size(unit, flags); + disk_parms->heads = 64; + disk_parms->sectors = 32; + disk_parms->cyls = sectors/(64 * 32); + disk_parms->secsiz = SECSIZE; + } + else + { + + if (sd_debug) + { + printf(" %d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n", + _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2), + scsi_sense.pages.rigid_geometry.nheads, + b2tol(scsi_sense.pages.rigid_geometry.st_cyl_wp), + b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc), + b2tol(scsi_sense.pages.rigid_geometry.land_zone)); + } + + /*******************************************************\ + * KLUDGE!!(for zone recorded disks) * + * give a number of sectors so that sec * trks * cyls * + * is <= disk_size * + \*******************************************************/ + disk_parms->heads = scsi_sense.pages.rigid_geometry.nheads; + disk_parms->cyls = _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2); + disk_parms->secsiz = _3btol(&scsi_sense.blk_desc.blklen); + + sectors = sd_size(unit, flags); + sectors /= disk_parms->cyls; + sectors /= disk_parms->heads; + disk_parms->sectors = sectors; /* dubious on SCSI*/ + } + + sd->flags |= SDVALID; + return(0); +} + +/*******************************************************\ +* close the device.. only called if we are the LAST * +* occurence of an open device * +\*******************************************************/ +sdclose(dev) +dev_t dev; +{ + unsigned char unit, part; + unsigned int old_priority; + + unit = UNIT(dev); + part = PARTITION(dev); + sd_data[unit].partflags[part] &= ~SDOPEN; + sd_data[unit].openparts &= ~(1 << part); + if(sd_data[unit].openparts == 0) /* if all partitions closed */ + { + sd_prevent(unit,PR_ALLOW,SCSI_SILENT|SCSI_ERR_OK); + } + return(0); +} + +/*******************************************************\ +* ask the scsi driver to perform a command for us. * +* Call it through the switch table, and tell it which * +* sub-unit we want, and what target and lu we wish to * +* talk to. Also tell it where to find the command * +* how long int is. * +* Also tell it where to read/write the data, and how * +* long the data is supposed to be * +\*******************************************************/ +int sd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) + +int unit,flags; +struct scsi_generic *scsi_cmd; +int cmdlen; +int timeout; +u_char *data_addr; +int datalen; +{ + struct scsi_xfer *xs; + int retval; + int s; + struct sd_data *sd = sd_data + unit; + + if(scsi_debug & PRINTROUTINES) printf("\nsd_scsi_cmd%d ",unit); + if(sd->sc_sw) /* If we have a scsi driver */ + { + xs = sd_get_xs(unit,flags); /* should wait unless booting */ + if(!xs) + { + printf("sd_scsi_cmd%d: controller busy" + " (this should never happen)\n",unit); + return(EBUSY); + } + xs->flags |= INUSE; + /*******************************************************\ + * Fill out the scsi_xfer structure * + \*******************************************************/ + xs->flags |= flags; + xs->adapter = sd->ctlr; + xs->targ = sd->targ; + xs->lu = sd->lu; + xs->retries = SD_RETRIES; + xs->timeout = timeout; + xs->cmd = scsi_cmd; + xs->cmdlen = cmdlen; + xs->data = data_addr; + xs->datalen = datalen; + xs->resid = datalen; + xs->when_done = (flags & SCSI_NOMASK) + ?(int (*)())0 + :sd_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; +retry: xs->error = XS_NOERROR; + xs->bp = 0; + retval = (*(sd->sc_sw->scsi_cmd))(xs); + switch(retval) + { + case SUCCESSFULLY_QUEUED: + s = splbio(); + while(!(xs->flags & ITSDONE)) + sleep(xs,PRIBIO+1); + splx(s); + + case HAD_ERROR: + /*printf("err = %d ",xs->error);*/ + switch(xs->error) + { + case XS_NOERROR: + retval = ESUCCESS; + break; + case XS_SENSE: + retval = (sd_interpret_sense(unit,xs)); + break; + case XS_DRIVER_STUFFUP: + retval = EIO; + break; + case XS_TIMEOUT: + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + goto retry; + } + retval = EIO; + break; + case XS_BUSY: + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + goto retry; + } + retval = EIO; + break; + default: + retval = EIO; + printf("sd%d: unknown error category from scsi driver\n" + ,unit); + } + break; + case COMPLETE: + retval = ESUCCESS; + break; + case TRY_AGAIN_LATER: + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + goto retry; + } + retval = EIO; + break; + default: + retval = EIO; + } + sd_free_xs(unit,xs,flags); + sdstart(unit); /* check if anything is waiting fr the xs */ + } + else + { + printf("sd%d: not set up\n",unit); + return(EINVAL); + } + return(retval); +} +/***************************************************************\ +* Look at the returned sense and act on the error and detirmine * +* The unix error number to pass back... (0 = report no error) * +\***************************************************************/ + +int sd_interpret_sense(unit,xs) +int unit; +struct scsi_xfer *xs; +{ + struct scsi_sense_data *sense; + int key; + int silent; + + /***************************************************************\ + * If the flags say errs are ok, then always return ok. * + \***************************************************************/ + if (xs->flags & SCSI_ERR_OK) return(ESUCCESS); + silent = (xs->flags & SCSI_SILENT); + + sense = &(xs->sense); + switch(sense->error_class) + { + case 7: + { + key=sense->ext.extended.sense_key; + switch(key) + { + case 0x0: + return(ESUCCESS); + case 0x1: + if(!silent) + { + printf("sd%d: soft error(corrected) ", unit); + if(sense->valid) + { + printf("block no. %d (decimal)", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + printf("\n"); + } + return(ESUCCESS); + case 0x2: + if(!silent)printf("sd%d: not ready\n ", + unit); + return(ENODEV); + case 0x3: + if(!silent) + { + printf("sd%d: medium error ", unit); + if(sense->valid) + { + printf("block no. %d (decimal)", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + printf("\n"); + } + return(EIO); + case 0x4: + if(!silent)printf("sd%d: non-media hardware failure\n ", + unit); + return(EIO); + case 0x5: + if(!silent)printf("sd%d: illegal request\n ", + unit); + return(EINVAL); + case 0x6: + /***********************************************\ + * If we are not open, then this is not an error * + * as we don't have state yet. Either way, make * + * sure that we don't have any residual state * + \***********************************************/ + if(!silent)printf("sd%d: Unit attention.\n ", unit); + sd_data[unit].flags &= ~(SDVALID | SDHAVELABEL); + if (sd_data[unit].openparts) + { + return(EIO); + } + return(ESUCCESS); /* not an error if nothing's open */ + case 0x7: + if(!silent) + { + printf("sd%d: attempted protection violation ", + unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + printf("\n"); + } + return(EACCES); + case 0x8: + if(!silent) + { + printf("sd%d: block wrong state (worm)\n ", + unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + printf("\n"); + } + return(EIO); + case 0x9: + if(!silent)printf("sd%d: vendor unique\n", + unit); + return(EIO); + case 0xa: + if(!silent)printf("sd%d: copy aborted\n ", + unit); + return(EIO); + case 0xb: + if(!silent)printf("sd%d: command aborted\n ", + unit); + return(EIO); + case 0xc: + if(!silent) + { + printf("sd%d: search returned\n ", + unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + printf("\n"); + } + return(ESUCCESS); + case 0xd: + if(!silent)printf("sd%d: volume overflow\n ", + unit); + return(ENOSPC); + case 0xe: + if(!silent) + { + printf("sd%d: verify miscompare\n ", + unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + printf("\n"); + } + return(EIO); + case 0xf: + if(!silent)printf("sd%d: unknown error key\n ", + unit); + return(EIO); + } + break; + } + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + { + if(!silent)printf("sd%d: error class %d code %d\n", + unit, + sense->error_class, + sense->error_code); + if(sense->valid) + if(!silent)printf("block no. %d (decimal)\n", + (sense->ext.unextended.blockhi <<16) + + (sense->ext.unextended.blockmed <<8) + + (sense->ext.unextended.blocklow )); + } + return(EIO); + } +} + + + + +int +sdsize(dev_t dev) +{ + int unit = UNIT(dev), part = PARTITION(dev), val; + struct sd_data *sd; + + if (unit >= NSD) + return(-1); + + sd = &sd_data[unit]; + if((sd->flags & SDINIT) == 0) return(-1); + if (sd == 0 || (sd->flags & SDHAVELABEL) == 0) + val = sdopen (MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0); + if ( val != 0 || sd->flags & SDWRITEPROT) + return (-1); + + return((int)sd->disklabel.d_partitions[part].p_size); +} + +sddump() +{ + printf("sddump() -- not implemented\n"); + return(-1); +} + + + + + diff --git a/sys/scsi/st.c b/sys/scsi/st.c new file mode 100644 index 000000000000..e8969025be2b --- /dev/null +++ b/sys/scsi/st.c @@ -0,0 +1,1774 @@ +/* + * Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + */ + +/* + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + */ + + +/* + * To do: + * work out some better way of guessing what a good timeout is going + * to be depending on whether we expect to retension or not. + * + */ + +#include <sys/types.h> +#include <st.h> + +#include <sys/param.h> +#include <sys/systm.h> + +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/mtio.h> + +#if defined(OSF) +#define SECSIZE 512 +#endif /* defined(OSF) */ + +#include <scsi/scsi_all.h> +#include <scsi/scsi_tape.h> +#include <scsi/scsiconf.h> + + +long int ststrats,stqueues; + + +#define PAGESIZ 4096 +#define STQSIZE 4 +#define ST_RETRIES 4 + + +#define MODE(z) ( (minor(z) & 0x03) ) +#define DSTY(z) ( ((minor(z) >> 2) & 0x03) ) +#define UNIT(z) ( (minor(z) >> 4) ) + +#define DSTY_QIC120 3 +#define DSTY_QIC150 2 +#define DSTY_QIC525 1 + +#define QIC120 0x0f +#define QIC150 0x10 +#define QIC525 0x11 + + + + +#ifndef __386BSD__ +struct buf stbuf[NST][STQSIZE]; /* buffer for raw io (one per device) */ +struct buf *stbuf_free[NST]; /* queue of free buffers for raw io */ +#endif __386BSD__ +struct buf st_buf_queue[NST]; +int ststrategy(); +void stminphys(); +struct scsi_xfer st_scsi_xfer[NST]; +int st_xfer_block_wait[NST]; + +#if defined(OSF) +caddr_t st_window[NST]; +#endif /* defined(OSF) */ +#ifndef MACH +#define ESUCCESS 0 +#endif MACH + +int st_info_valid[NST]; /* the info about the device is valid */ +int st_initialized[NST] ; +int st_debug = 0; + +int stattach(); +int st_done(); +struct st_data +{ + int flags; + struct scsi_switch *sc_sw; /* address of scsi low level switch */ + int ctlr; /* so they know which one we want */ + int targ; /* our scsi target ID */ + int lu; /* out scsi lu */ + int blkmin; /* min blk size */ + int blkmax; /* max blk size */ + int numblks; /* nominal blocks capacity */ + int blksiz; /* nominal block size */ +}st_data[NST]; +#define ST_OPEN 0x01 +#define ST_NOREWIND 0x02 +#define ST_WRITTEN 0x04 +#define ST_FIXEDBLOCKS 0x10 +#define ST_AT_FILEMARK 0x20 +#define ST_AT_EOM 0x40 + +#define ST_PER_ACTION (ST_AT_FILEMARK | ST_AT_EOM) +#define ST_PER_OPEN (ST_OPEN | ST_NOREWIND | ST_WRITTEN | ST_PER_ACTION) +#define ST_PER_MEDIA ST_FIXEDBLOCKS + +static int next_st_unit = 0; +/***********************************************************************\ +* The routine called by the low level scsi routine when it discovers * +* A device suitable for this driver * +\***********************************************************************/ + +int stattach(ctlr,targ,lu,scsi_switch) +struct scsi_switch *scsi_switch; +{ + int unit,i; + unsigned char *tbl; + struct st_data *st; + + if(scsi_debug & PRINTROUTINES) printf("stattach: "); + /*******************************************************\ + * Check we have the resources for another drive * + \*******************************************************/ + unit = next_st_unit++; + if( unit >= NST) + { + printf("Too many scsi tapes..(%d > %d) reconfigure kernel",(unit + 1),NST); + return(0); + } + st = st_data + unit; + /*******************************************************\ + * Store information needed to contact our base driver * + \*******************************************************/ + st->sc_sw = scsi_switch; + st->ctlr = ctlr; + st->targ = targ; + st->lu = lu; + + /*******************************************************\ + * Use the subdriver to request information regarding * + * the drive. We cannot use interrupts yet, so the * + * request must specify this. * + \*******************************************************/ + if((st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT))) + { + printf(" st%d: scsi tape drive, %d blocks of %d bytes\n", + unit, st->numblks, st->blksiz); + } + else + { + printf(" st%d: scsi tape drive :- offline\n", unit); + } + /*******************************************************\ + * Set up the bufs for this device * + \*******************************************************/ +#ifndef __386BSD__ + stbuf_free[unit] = (struct buf *)0; + for (i = 1; i < STQSIZE; i++) + { + stbuf[unit][i].b_forw = stbuf_free[unit]; + stbuf_free[unit]=&stbuf[unit][i]; + } +#endif __386BSD__ + st_buf_queue[unit].b_active = 0; + st_buf_queue[unit].b_actf = st_buf_queue[unit].b_actl = 0; + st_initialized[unit] = 1; + +#if defined(OSF) + st_window[unit] = (caddr_t)alloc_kva(SECSIZE*256+PAGESIZ); +#endif /* defined(OSF) */ + + return; + +} + + + +/*******************************************************\ +* open the device. * +\*******************************************************/ +stopen(dev) +{ + int errcode = 0; + int unit,mode,dsty; + int dsty_code; + struct st_data *st; + unit = UNIT(dev); + mode = MODE(dev); + dsty = DSTY(dev); + st = st_data + unit; + + /*******************************************************\ + * Check the unit is legal * + \*******************************************************/ + if ( unit >= NST ) + { + errcode = ENXIO; + return(errcode); + } + /*******************************************************\ + * Only allow one at a time * + \*******************************************************/ + if(st->flags & ST_OPEN) + { + errcode = ENXIO; + goto bad; + } + /*******************************************************\ + * Set up the mode flags according to the minor number * + * ensure all open flags are in a known state * + \*******************************************************/ + st->flags &= ~ST_PER_OPEN; + switch(mode) + { + case 2: + case 0: + st->flags &= ~ST_NOREWIND; + break; + case 3: + case 1: + st->flags |= ST_NOREWIND; + break; + default: + printf("st%d: Bad mode (minor number)%d\n",unit,mode); + return(EINVAL); + } + /*******************************************************\ + * Check density code: 0 is drive default * + \*******************************************************/ + switch(dsty) + { + case 0: dsty_code = 0; break; + case DSTY_QIC120: dsty_code = QIC120; break; + case DSTY_QIC150: dsty_code = QIC150; break; + case DSTY_QIC525: dsty_code = QIC525; break; + default: + printf("st%d: Bad density (minor number)%d\n",unit,dsty); + return(EINVAL); + } + if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) + printf("stopen: dev=0x%x (unit %d (of %d))\n" + , dev, unit, NST); + /*******************************************************\ + * Make sure the device has been initialised * + \*******************************************************/ + + if (!st_initialized[unit]) + return(ENXIO); + /*******************************************************\ + * Check that it is still responding and ok. * + \*******************************************************/ + + if(scsi_debug & TRACEOPENS) + printf("device is "); + if (!(st_req_sense(unit, 0))) + { + errcode = ENXIO; + if(scsi_debug & TRACEOPENS) + printf("not responding\n"); + goto bad; + } + if(scsi_debug & TRACEOPENS) + printf("ok\n"); + + if(!(st_test_ready(unit,0))) + { + printf("st%d not ready\n",unit); + return(EIO); + } + + if(!st_info_valid[unit]) /* is media new? */ + if(!st_load(unit,LD_LOAD,0)) + { + return(EIO); + } + + if(!st_rd_blk_lim(unit,0)) + { + return(EIO); + } + + if(!st_mode_sense(unit,0)) + { + return(EIO); + } + + if(!st_mode_select(unit,0,dsty_code)) + { + return(EIO); + } + + st_info_valid[unit] = TRUE; + + st_prevent(unit,PR_PREVENT,0); /* who cares if it fails? */ + + /*******************************************************\ + * Load the physical device parameters * + \*******************************************************/ + if(scsi_debug & TRACEOPENS) + printf("Params loaded "); + + + st->flags |= ST_OPEN; + +bad: + return(errcode); +} + +/*******************************************************\ +* close the device.. only called if we are the LAST * +* occurence of an open device * +\*******************************************************/ +stclose(dev) +{ + unsigned char unit,mode; + struct st_data *st; + + unit = UNIT(dev); + mode = MODE(dev); + st = st_data + unit; + + if(scsi_debug & TRACEOPENS) + printf("Closing device"); + if(st->flags & ST_WRITTEN) + { + st_write_filemarks(unit,1,0); + } + st->flags &= ~ST_WRITTEN; + switch(mode) + { + case 0: + st_rewind(unit,FALSE,SCSI_SILENT); + st_prevent(unit,PR_ALLOW,SCSI_SILENT); + break; + case 1: + st_prevent(unit,PR_ALLOW,SCSI_SILENT); + break; + case 2: + st_rewind(unit,FALSE,SCSI_SILENT); + st_prevent(unit,PR_ALLOW,SCSI_SILENT); + st_load(unit,LD_UNLOAD,SCSI_SILENT); + break; + case 3: + st_prevent(unit,PR_ALLOW,SCSI_SILENT); + st_load(unit,LD_UNLOAD,SCSI_SILENT); + break; + default: + printf("st%d:close: Bad mode (minor number)%d how's it open?\n" + ,unit,mode); + return(EINVAL); + } + st->flags &= ~ST_PER_OPEN; + return(0); +} + +#ifndef __386BSD__ +/*******************************************************\ +* Get ownership of this unit's buf * +* If need be, sleep on it, until it comes free * +\*******************************************************/ +struct buf * +st_get_buf(unit) { + struct buf *rc; + + while (!(rc = stbuf_free[unit])) + sleep((caddr_t)&stbuf_free[unit], PRIBIO+1); + stbuf_free[unit] = stbuf_free[unit]->b_forw; + rc->b_error = 0; + rc->b_resid = 0; + rc->b_flags = 0; + return(rc); +} + +/*******************************************************\ +* Free this unit's buf, wake processes waiting for it * +\*******************************************************/ +st_free_buf(unit,bp) +struct buf *bp; +{ + if (!stbuf_free[unit]) + wakeup((caddr_t)&stbuf_free[unit]); + bp->b_forw = stbuf_free[unit]; + stbuf_free[unit] = bp; +} + + +/*******************************************************\ +* Get the buf for this unit and use physio to do it * +\*******************************************************/ +stread(dev,uio) +register short dev; +struct uio *uio; +{ + int unit = UNIT(dev); + struct buf *bp = st_get_buf(unit); + int rc; + rc = physio(ststrategy, bp, dev, B_READ, stminphys, uio); + st_free_buf(unit,bp); + return(rc); +} + +/*******************************************************\ +* Get the buf for this unit and use physio to do it * +\*******************************************************/ +stwrite(dev,uio) +dev_t dev; +struct uio *uio; +{ + int unit = UNIT(dev); + struct buf *bp = st_get_buf(unit); + int rc; + + rc = physio(ststrategy, bp, dev, B_WRITE, stminphys, uio); + st_free_buf(unit,bp); + return(rc); +} + + +#endif __386BSD__ +/*******************************************************\ +* trim the size of the transfer if needed, * +* called by physio * +* basically the smaller of our min and the scsi driver's* +* minphys * +\*******************************************************/ +void stminphys(bp) +struct buf *bp; +{ + (*(st_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp); +} + +/*******************************************************\ +* Actually translate the requested transfer into * +* one the physical driver can understand * +* The transfer is described by a buf and will include * +* only one physical transfer. * +\*******************************************************/ + +int ststrategy(bp) +struct buf *bp; +{ + struct buf *dp; + unsigned char unit; + unsigned int opri; + + ststrats++; + unit = UNIT((bp->b_dev)); + if(scsi_debug & PRINTROUTINES) printf("\nststrategy "); + if(scsi_debug & SHOWREQUESTS) printf("st%d: %d bytes @ blk%d\n", + unit,bp->b_bcount,bp->b_blkno); + /*******************************************************\ + * If it's a null transfer, return immediatly * + \*******************************************************/ + if (bp->b_bcount == 0) { + goto done; + } + + /*******************************************************\ + * Odd sized request on fixed drives are verboten * + \*******************************************************/ + if((st_data[unit].flags & ST_FIXEDBLOCKS) + && bp->b_bcount % st_data[unit].blkmin) + { + printf("st%d: bad request, must be multiple of %d\n", + unit, st_data[unit].blkmin); + bp->b_error = EIO; + goto bad; + } + +#ifdef __386BSD__ + stminphys(bp); +#endif __386BSD__ + opri = splbio(); + dp = &st_buf_queue[unit]; + + /*******************************************************\ + * Place it in the queue of disk activities for this tape* + * at the end * + \*******************************************************/ + while ( dp->b_actf) + { + dp = dp->b_actf; + } + dp->b_actf = bp; + bp->b_actf = NULL; + + /*******************************************************\ + * Tell the device to get going on the transfer if it's * + * not doing anything, otherwise just wait for completion* + \*******************************************************/ + ststart(unit); + + splx(opri); + return; +bad: + bp->b_flags |= B_ERROR; +done: + /*******************************************************\ + * Correctly set the buf to indicate a completed xfer * + \*******************************************************/ + iodone(bp); + return; +} + + +/***************************************************************\ +* ststart looks to see if there is a buf waiting for the device * +* and that the device is not already busy. If both are true, * +* It deques the buf and creates a scsi command to perform the * +* transfer in the buf. The transfer request will call st_done * +* on completion, which will in turn call this routine again * +* so that the next queued transfer is performed. * +* The bufs are queued by the strategy routine (ststrategy) * +* * +* This routine is also called after other non-queued requests * +* have been made of the scsi driver, to ensure that the queue * +* continues to be drained. * +\***************************************************************/ +/* ststart() is called at splbio */ +ststart(unit) +{ + int drivecount; + register struct buf *bp = 0; + register struct buf *dp; + struct scsi_xfer *xs; + struct scsi_rw_tape cmd; + int blkno, nblk; + struct st_data *st; + + + st = st_data + unit; + + if(scsi_debug & PRINTROUTINES) printf("ststart%d ",unit); + /*******************************************************\ + * See if there is a buf to do and we are not already * + * doing one * + \*******************************************************/ + xs=&st_scsi_xfer[unit]; + if(xs->flags & INUSE) + { + return; /* unit already underway */ + } +trynext: + if(st_xfer_block_wait[unit]) /* a special awaits, let it proceed first */ + { + wakeup(&st_xfer_block_wait[unit]); + return; + } + + dp = &st_buf_queue[unit]; + if ((bp = dp->b_actf) != NULL) + { + dp->b_actf = bp->b_actf; + } + else /* no work to do */ + { + return; + } + xs->flags = INUSE; /* Now ours */ + + + /*******************************************************\ + * We have a buf, now we should move the data into * + * a scsi_xfer definition and try start it * + \*******************************************************/ + + /*******************************************************\ + * If we are at a filemark but have not reported it yet * + * then we should report it now * + \*******************************************************/ + if(st->flags & ST_AT_FILEMARK) + { + bp->b_error = 0; + bp->b_flags |= B_ERROR; /* EOF*/ + st->flags &= ~ST_AT_FILEMARK; + biodone(bp); + xs->flags = 0; /* won't need it now */ + goto trynext; + } + /*******************************************************\ + * If we are at EOM but have not reported it yet * + * then we should report it now * + \*******************************************************/ + if(st->flags & ST_AT_EOM) + { + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + st->flags &= ~ST_AT_EOM; + biodone(bp); + xs->flags = 0; /* won't need it now */ + goto trynext; + } + /*******************************************************\ + * Fill out the scsi command * + \*******************************************************/ + bzero(&cmd, sizeof(cmd)); + if((bp->b_flags & B_READ) == B_WRITE) + { + st->flags |= ST_WRITTEN; + xs->flags |= SCSI_DATA_OUT; + } + else + { + xs->flags |= SCSI_DATA_IN; + } + cmd.op_code = (bp->b_flags & B_READ) + ? READ_COMMAND_TAPE + : WRITE_COMMAND_TAPE; + + /*******************************************************\ + * Handle "fixed-block-mode" tape drives by using the * + * block count instead of the length. * + \*******************************************************/ + if(st->flags & ST_FIXEDBLOCKS) + { + cmd.fixed = 1; + lto3b(bp->b_bcount/st->blkmin,cmd.len); + } + else + { + lto3b(bp->b_bcount,cmd.len); + } + + /*******************************************************\ + * Fill out the scsi_xfer structure * + * Note: we cannot sleep as we may be an interrupt * + \*******************************************************/ + xs->flags |= SCSI_NOSLEEP; + xs->adapter = st->ctlr; + xs->targ = st->targ; + xs->lu = st->lu; + xs->retries = 1; /* can't retry on tape*/ + xs->timeout = 100000; /* allow 100 secs for retension */ + xs->cmd = (struct scsi_generic *)&cmd; + xs->cmdlen = sizeof(cmd); + xs->data = (u_char *)bp->b_un.b_addr; + xs->datalen = bp->b_bcount; + xs->resid = bp->b_bcount; + xs->when_done = st_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; + xs->error = XS_NOERROR; + xs->bp = bp; + /*******************************************************\ + * Pass all this info to the scsi driver. * + \*******************************************************/ + + +#if defined(OSF)||defined(FIX_ME) + if (bp->b_flags & B_PHYS) { + xs->data = (u_char*)map_pva_kva(bp->b_proc, bp->b_un.b_addr, + bp->b_bcount, st_window[unit], + (bp->b_flags&B_READ)?B_WRITE:B_READ); + } else { + xs->data = (u_char*)bp->b_un.b_addr; + } +#endif /* defined(OSF) */ + + if ( (*(st->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED) + { + printf("st%d: oops not queued",unit); + xs->error = XS_DRIVER_STUFFUP; + st_done(unit,xs); + } + stqueues++; +} + +/*******************************************************\ +* This routine is called by the scsi interrupt when * +* the transfer is complete. +\*******************************************************/ +int st_done(unit,xs) +int unit; +struct scsi_xfer *xs; +{ + struct buf *bp; + int retval; + + if(scsi_debug & PRINTROUTINES) printf("st_done%d ",unit); + if (! (xs->flags & INUSE)) + panic("scsi_xfer not in use!"); + if(bp = xs->bp) + { + switch(xs->error) + { + case XS_NOERROR: + bp->b_flags &= ~B_ERROR; + bp->b_error = 0; + bp->b_resid = 0; + break; + case XS_SENSE: + retval = (st_interpret_sense(unit,xs)); + if(retval) + { + /***************************************\ + * We have a real error, the bit should * + * be set to indicate this. The return * + * value will contain the unix error code* + * that the error interpretation routine * + * thought was suitable, so pass this * + * value back in the buf structure. * + * Furthermore we return information * + * saying that no data was transferred * + \***************************************/ + bp->b_flags |= B_ERROR; + bp->b_error = retval; + bp->b_resid = bp->b_bcount; + st_data[unit].flags + &= ~(ST_AT_FILEMARK|ST_AT_EOM); + } + else + { + /***********************************************\ + * The error interpretation code has declared * + * that it wasn't a real error, or at least that * + * we should be ignoring it if it was. * + \***********************************************/ + if(xs->resid && ( xs->resid != xs->datalen )) + { + /***************************************\ + * Here we have the tricky part.. * + * We successfully read less data than * + * we requested. (but not 0) * + *------for variable blocksize tapes:----* + * UNDER 386BSD: * + * We should legitimatly have the error * + * bit set, with the error value set to * + * zero.. This is to indicate to the * + * physio code that while we didn't get * + * as much information as was requested, * + * we did reach the end of the record * + * and so physio should not call us * + * again for more data... we have it all * + * SO SET THE ERROR BIT! * + * * + * UNDER MACH:(CMU) * + * To indicate the same as above, we * + * need only have a non 0 resid that is * + * less than the b_bcount, but the * + * ERROR BIT MUST BE CLEAR! (sigh) * + * * + * UNDER OSF1: * + * To indicate the same as above, we * + * need to have a non 0 resid that is * + * less than the b_bcount, but the * + * ERROR BIT MUST BE SET! (gasp)(sigh) * + * * + *-------for fixed blocksize device------* + * We could have read some successful * + * records before hitting * + * the EOF or EOT. These must be passed * + * to the user, before we report the * + * EOx. Only if there is no data for the * + * user do we report it now. (via an EIO * + * for EOM and resid == count for EOF). * + * We will report the EOx NEXT time.. * + \***************************************/ +#ifdef MACH /*osf and cmu varieties */ +#ifdef OSF + bp->b_flags |= B_ERROR; +#else OSF + bp->b_flags &= ~B_ERROR; +#endif OSF +#endif MACH +#ifdef __386BSD__ + bp->b_flags |= B_ERROR; +#endif __386BSD__ + bp->b_error = 0; + bp->b_resid = xs->resid; + if((st_data[unit].flags & ST_FIXEDBLOCKS)) + { + bp->b_resid *= st_data[unit].blkmin; + if( (st_data[unit].flags & ST_AT_EOM) + && (bp->b_resid == bp->b_bcount)) + { + bp->b_error = EIO; + st_data[unit].flags + &= ~ST_AT_EOM; + } + } + xs->error = XS_NOERROR; + break; + } + else + { + /***************************************\ + * We have come out of the error handler * + * with no error code.. we have also * + * not had an ili (would have gone to * + * the previous clause). Now we need to * + * distiguish between succesful read of * + * no data (EOF or EOM) and successfull * + * read of all requested data. * + * At least all o/s agree that: * + * 0 bytes read with no error is EOF * + * 0 bytes read with an EIO is EOM * + \***************************************/ + + bp->b_resid = bp->b_bcount; + if(st_data[unit].flags & ST_AT_FILEMARK) + { + st_data[unit].flags &= ~ST_AT_FILEMARK; + bp->b_flags &= ~B_ERROR; + bp->b_error = 0; + break; + } + if(st_data[unit].flags & ST_AT_EOM) + { + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + st_data[unit].flags &= ~ST_AT_EOM; + break; + } + printf("st%d:error ignored\n" ,unit); + } + } + break; + + case XS_TIMEOUT: + printf("st%d timeout\n",unit); + break; + + case XS_BUSY: /* should retry */ /* how? */ + /************************************************/ + /* SHOULD put buf back at head of queue */ + /* and decrement retry count in (*xs) */ + /* HOWEVER, this should work as a kludge */ + /************************************************/ + if(xs->retries--) + { + xs->flags &= ~ITSDONE; + xs->error = XS_NOERROR; + if ( (*(st_data[unit].sc_sw->scsi_cmd))(xs) + == SUCCESSFULLY_QUEUED) + { /* don't wake the job, ok? */ + return; + } + printf("device busy"); + xs->flags |= ITSDONE; + } + + case XS_DRIVER_STUFFUP: + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + break; + default: + printf("st%d: unknown error category from scsi driver\n" + ,unit); + } + biodone(bp); + xs->flags = 0; /* no longer in use */ + ststart(unit); /* If there's another waiting.. do it */ + } + else + { + wakeup(xs); + } +} +/*******************************************************\ +* Perform special action on behalf of the user * +* Knows about the internals of this device * +\*******************************************************/ +stioctl(dev, cmd, arg, mode) +dev_t dev; +int cmd; +caddr_t arg; +{ + register i,j; + unsigned int opri; + int errcode = 0; + unsigned char unit; + int number,flags,ret; + + /*******************************************************\ + * Find the device that the user is talking about * + \*******************************************************/ + flags = 0; /* give error messages, act on errors etc. */ + unit = UNIT(dev); + + switch(cmd) + { + + case MTIOCGET: + { + struct mtget *g = (struct mtget *) arg; + + bzero(g, sizeof(struct mtget)); + g->mt_type = 0x7; /* Ultrix compat */ /*?*/ + ret=TRUE; + break; + } + + + case MTIOCTOP: + { + struct mtop *mt = (struct mtop *) arg; + + if (st_debug) + printf("[sctape_sstatus: %x %x]\n", + mt->mt_op, mt->mt_count); + + + + /* compat: in U*x it is a short */ + number = mt->mt_count; + switch ((short)(mt->mt_op)) + { + case MTWEOF: /* write an end-of-file record */ + ret = st_write_filemarks(unit,number,flags); + st_data[unit].flags &= ~ST_WRITTEN; + break; + case MTFSF: /* forward space file */ + ret = st_space(unit,number,SP_FILEMARKS,flags); + break; + case MTBSF: /* backward space file */ + ret = st_space(unit,-number,SP_FILEMARKS,flags); + break; + case MTFSR: /* forward space record */ + ret = st_space(unit,number,SP_BLKS,flags); + break; + case MTBSR: /* backward space record */ + ret = st_space(unit,-number,SP_BLKS,flags); + break; + case MTREW: /* rewind */ + ret = st_rewind(unit,FALSE,flags); + break; + case MTOFFL: /* rewind and put the drive offline */ + if((ret = st_rewind(unit,FALSE,flags))) + { + st_prevent(unit,PR_ALLOW,0); + ret = st_load(unit,LD_UNLOAD,flags); + } + else + { + printf("rewind failed, unit still loaded\n"); + } + break; + case MTNOP: /* no operation, sets status only */ + case MTCACHE: /* enable controller cache */ + case MTNOCACHE: /* disable controller cache */ + ret = TRUE;; + break; + default: + return EINVAL; + } + break; + } + case MTIOCIEOT: + case MTIOCEEOT: + ret=TRUE; + break; + } + + return(ret?ESUCCESS:EIO); +} + + +/*******************************************************\ +* Check with the device that it is ok, (via scsi driver)* +\*******************************************************/ +st_req_sense(unit, flags) +int flags; +{ + struct scsi_sense_data sense; + struct scsi_sense scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = REQUEST_SENSE; + scsi_cmd.length = sizeof(sense); + + if (st_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + &sense, + sizeof(sense), + 100000, + flags | SCSI_DATA_IN) != 0) + { + return(FALSE); + } + else + return(TRUE); +} + +/*******************************************************\ +* Get scsi driver to send a "are you ready" command * +\*******************************************************/ +st_test_ready(unit,flags) +int unit,flags; +{ + struct scsi_test_unit_ready scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = TEST_UNIT_READY; + + if (st_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 100000, + flags) != 0) { + return(FALSE); + } else + return(TRUE); +} + + +#ifdef __STDC__ +#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) +#else +#define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 ) +#endif + +/*******************************************************\ +* Ask the drive what it's min and max blk sizes are. * +\*******************************************************/ +st_rd_blk_lim(unit, flags) +int unit,flags; +{ + struct scsi_blk_limits scsi_cmd; + struct scsi_blk_limits_data scsi_blkl; + struct st_data *st = st_data + unit; + /*******************************************************\ + * First check if we have it all loaded * + \*******************************************************/ + if (st_info_valid[unit]) goto done; + + /*******************************************************\ + * do a 'Read Block Limits' * + \*******************************************************/ + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = READ_BLK_LIMITS; + + /*******************************************************\ + * do the command, update the global values * + \*******************************************************/ + if (st_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + &scsi_blkl, + sizeof(scsi_blkl), + 5000, + flags | SCSI_DATA_IN) != 0) + { + if(!(flags & SCSI_SILENT)) + printf("could not get blk limits for unit %d\n", unit); + st_info_valid[unit] = FALSE; + return(FALSE); + } + if (st_debug) + { + printf(" (%d <= blksiz <= %d\n) ", + b2tol(scsi_blkl.min_length), + _3btol(&scsi_blkl.max_length_2)); + } + st->blkmin = b2tol(scsi_blkl.min_length); + st->blkmax = _3btol(&scsi_blkl.max_length_2); + +done: + if(st->blkmin && (st->blkmin == st->blkmax)) + { + st->flags |= ST_FIXEDBLOCKS; + } + return(TRUE); +} +/*******************************************************\ +* Get the scsi driver to send a full inquiry to the * +* device and use the results to fill out the global * +* parameter structure. * +\*******************************************************/ +st_mode_sense(unit, flags) +int unit,flags; +{ + struct scsi_mode_sense scsi_cmd; + struct + { + struct scsi_mode_header_tape header; + struct blk_desc blk_desc; + }scsi_sense; + struct st_data *st = st_data + unit; + + /*******************************************************\ + * First check if we have it all loaded * + \*******************************************************/ + if (st_info_valid[unit]) return(TRUE); + /*******************************************************\ + * First do a mode sense * + \*******************************************************/ + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = MODE_SENSE; + scsi_cmd.length = sizeof(scsi_sense); + /*******************************************************\ + * do the command, but we don't need the results * + * just print them for our interest's sake * + \*******************************************************/ + if (st_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + &scsi_sense, + sizeof(scsi_sense), + 5000, + flags | SCSI_DATA_IN) != 0) + { + if(!(flags & SCSI_SILENT)) + printf("could not mode sense for unit %d\n", unit); + st_info_valid[unit] = FALSE; + return(FALSE); + } + if (st_debug) + { + printf("unit %d: %d blocks of %d bytes, write %s, %sbuffered", + unit, + _3btol(&scsi_sense.blk_desc.nblocks), + _3btol(&scsi_sense.blk_desc.blklen), + (scsi_sense.header.write_protected ? + "protected" : "enabled"), + (scsi_sense.header.buf_mode ? + "" : "un") + ); + } + st->numblks = _3btol(&scsi_sense.blk_desc.nblocks); + st->blksiz = _3btol(&scsi_sense.blk_desc.blklen); + return(TRUE); +} + +/*******************************************************\ +* Get the scsi driver to send a full inquiry to the * +* device and use the results to fill out the global * +* parameter structure. * +\*******************************************************/ +st_mode_select(unit, flags, dsty_code) +int unit,flags,dsty_code; +{ + struct scsi_mode_select scsi_cmd; + struct + { + struct scsi_mode_header_tape header; + struct blk_desc blk_desc; + }dat; + struct st_data *st = st_data + unit; + + /*******************************************************\ + * Set up for a mode select * + \*******************************************************/ + bzero(&dat, sizeof(dat)); + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = MODE_SELECT; + scsi_cmd.length = sizeof(dat); + dat.header.blk_desc_len = sizeof(struct blk_desc); + dat.header.buf_mode = 1; + dat.blk_desc.density = dsty_code; + if(st->flags & ST_FIXEDBLOCKS) + { + lto3b( st->blkmin , dat.blk_desc.blklen); + } +/* lto3b( st->numblks , dat.blk_desc.nblocks); use defaults!!!! + lto3b( st->blksiz , dat.blk_desc.blklen); +*/ + /*******************************************************\ + * do the command * + \*******************************************************/ + if (st_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + &dat, + sizeof(dat), + 5000, + flags | SCSI_DATA_OUT) != 0) + { + if(!(flags & SCSI_SILENT)) + printf("could not mode select for unit %d\n", unit); + st_info_valid[unit] = FALSE; + return(FALSE); + } + return(TRUE); +} + +/*******************************************************\ +* skip N blocks/filemarks/seq filemarks/eom * +\*******************************************************/ +st_space(unit,number,what,flags) +int unit,number,what,flags; +{ + struct scsi_space scsi_cmd; + + /* if we are at a filemark now, we soon won't be*/ + st_data[unit].flags &= ~(ST_AT_FILEMARK | ST_AT_EOM); + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = SPACE; + scsi_cmd.code = what; + lto3b(number,scsi_cmd.number); + if (st_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 600000, /* 10 mins enough? */ + flags) != 0) + { + if(!(flags & SCSI_SILENT)) + printf("could not space st%d\n", unit); + st_info_valid[unit] = FALSE; + return(FALSE); + } + return(TRUE); +} +/*******************************************************\ +* write N filemarks * +\*******************************************************/ +st_write_filemarks(unit,number,flags) +int unit,number,flags; +{ + struct scsi_write_filemarks scsi_cmd; + + st_data[unit].flags &= ~(ST_AT_FILEMARK); + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = WRITE_FILEMARKS; + lto3b(number,scsi_cmd.number); + if (st_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 100000, /* 10 secs.. (may need to repos head )*/ + flags) != 0) + { + if(!(flags & SCSI_SILENT)) + printf("could not write_filemarks st%d\n", unit); + st_info_valid[unit] = FALSE; + return(FALSE); + } + return(TRUE); +} +/*******************************************************\ +* load /unload (with retension if true) * +\*******************************************************/ +st_load(unit,type,flags) +int unit,type,flags; +{ + struct scsi_load scsi_cmd; + + st_data[unit].flags &= ~(ST_AT_FILEMARK | ST_AT_EOM); + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = LOAD_UNLOAD; + scsi_cmd.load=type; + if (type == LD_LOAD) + { + /*scsi_cmd.reten=TRUE;*/ + scsi_cmd.reten=FALSE; + } + else + { + scsi_cmd.reten=FALSE; + } + if (st_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 30000, /* 30 secs */ + flags) != 0) + { + if(!(flags & SCSI_SILENT)) + printf("cannot load/unload st%d\n", unit); + st_info_valid[unit] = FALSE; + return(FALSE); + } + return(TRUE); +} +/*******************************************************\ +* Prevent or allow the user to remove the tape * +\*******************************************************/ +st_prevent(unit,type,flags) +int unit,type,flags; +{ + struct scsi_prevent scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = PREVENT_ALLOW; + scsi_cmd.prevent=type; + if (st_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 5000, + flags) != 0) + { + if(!(flags & SCSI_SILENT)) + printf("cannot prevent/allow on st%d\n", unit); + st_info_valid[unit] = FALSE; + return(FALSE); + } + return(TRUE); +} +/*******************************************************\ +* Rewind the device * +\*******************************************************/ +st_rewind(unit,immed,flags) +int unit,immed,flags; +{ + struct scsi_rewind scsi_cmd; + + st_data[unit].flags &= ~(ST_AT_FILEMARK | ST_AT_EOM); + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = REWIND; + scsi_cmd.immed=immed; + if (st_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + immed?5000:300000, /* 5 sec or 5 min */ + flags) != 0) + { + if(!(flags & SCSI_SILENT)) + printf("could not rewind st%d\n", unit); + st_info_valid[unit] = FALSE; + return(FALSE); + } + return(TRUE); +} +/*******************************************************\ +* ask the scsi driver to perform a command for us. * +* Call it through the switch table, and tell it which * +* sub-unit we want, and what target and lu we wish to * +* talk to. Also tell it where to find the command * +* how long int is. * +* Also tell it where to read/write the data, and how * +* long the data is supposed to be * +\*******************************************************/ +int st_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) + +int unit,flags; +struct scsi_generic *scsi_cmd; +int cmdlen; +int timeout; +u_char *data_addr; +int datalen; +{ + struct scsi_xfer *xs; + int retval; + int s; + struct st_data *st = st_data + unit; + + if(scsi_debug & PRINTROUTINES) printf("\nst_scsi_cmd%d ",unit); + if(st->sc_sw) /* If we have a scsi driver */ + { + + xs = &(st_scsi_xfer[unit]); + if(!(flags & SCSI_NOMASK)) + s = splbio(); + st_xfer_block_wait[unit]++; /* there is someone waiting */ + while (xs->flags & INUSE) + { + sleep(&st_xfer_block_wait[unit],PRIBIO+1); + } + st_xfer_block_wait[unit]--; + xs->flags = INUSE; + if(!(flags & SCSI_NOMASK)) + splx(s); + + /*******************************************************\ + * Fill out the scsi_xfer structure * + \*******************************************************/ + xs->flags |= flags; + xs->adapter = st->ctlr; + xs->targ = st->targ; + xs->lu = st->lu; + xs->retries = ST_RETRIES; + xs->timeout = timeout; + xs->cmd = scsi_cmd; + xs->cmdlen = cmdlen; + xs->data = data_addr; + xs->datalen = datalen; + xs->resid = datalen; + xs->when_done = (flags & SCSI_NOMASK) + ?(int (*)())0 + :st_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; +retry: xs->error = XS_NOERROR; + xs->bp = 0; + retval = (*(st->sc_sw->scsi_cmd))(xs); + switch(retval) + { + case SUCCESSFULLY_QUEUED: + s = splbio(); + while(!(xs->flags & ITSDONE)) + sleep(xs,PRIBIO+1); + splx(s); + + case HAD_ERROR: + case COMPLETE: + switch(xs->error) + { + case XS_NOERROR: + retval = ESUCCESS; + break; + case XS_SENSE: + retval = (st_interpret_sense(unit,xs)); + /* only useful for reads */ + if (retval) + { /* error... don't care about filemarks */ + st->flags &= ~(ST_AT_FILEMARK + | ST_AT_EOM); + } + else + { + xs->error = XS_NOERROR; + retval = ESUCCESS; + } + break; + case XS_DRIVER_STUFFUP: + retval = EIO; + break; + case XS_TIMEOUT: + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + goto retry; + } + retval = EIO; + break; + case XS_BUSY: + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + goto retry; + } + retval = EIO; + break; + default: + retval = EIO; + printf("st%d: unknown error category from scsi driver\n" + ,unit); + break; + } + break; + case TRY_AGAIN_LATER: + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + goto retry; + } + retval = EIO; + break; + default: + retval = EIO; + } + xs->flags = 0; /* it's free! */ + ststart(unit); + } + else + { + printf("st%d: not set up\n",unit); + return(EINVAL); + } + return(retval); +} +/***************************************************************\ +* Look at the returned sense and act on the error and detirmine * +* The unix error number to pass back... (0 = report no error) * +\***************************************************************/ + +int st_interpret_sense(unit,xs) +int unit; +struct scsi_xfer *xs; +{ + struct scsi_sense_data *sense; + int key; + int silent = xs->flags & SCSI_SILENT; + + /***************************************************************\ + * If errors are ok, report a success * + \***************************************************************/ + if(xs->flags & SCSI_ERR_OK) return(ESUCCESS); + + /***************************************************************\ + * Get the sense fields and work out what CLASS * + \***************************************************************/ + sense = &(xs->sense); + if(st_debug) + { + int count = 0; + printf("code%x class%x valid%x\n" + ,sense->error_code + ,sense->error_class + ,sense->valid); + printf("seg%x key%x ili%x eom%x fmark%x\n" + ,sense->ext.extended.segment + ,sense->ext.extended.sense_key + ,sense->ext.extended.ili + ,sense->ext.extended.eom + ,sense->ext.extended.filemark); + printf("info: %x %x %x %x followed by %d extra bytes\n" + ,sense->ext.extended.info[0] + ,sense->ext.extended.info[1] + ,sense->ext.extended.info[2] + ,sense->ext.extended.info[3] + ,sense->ext.extended.extra_len); + printf("extra: "); + while(count < sense->ext.extended.extra_len) + { + printf ("%x ",sense->ext.extended.extra_bytes[count++]); + } + printf("\n"); + } + switch(sense->error_class) + { + /***************************************************************\ + * If it's class 7, use the extended stuff and interpret the key * + \***************************************************************/ + case 7: + { + if(sense->ext.extended.eom) + { + st_data[unit].flags |= ST_AT_EOM; + } + + if(sense->ext.extended.filemark) + { + st_data[unit].flags |= ST_AT_FILEMARK; + } + + if(sense->ext.extended.ili) + { + if(sense->valid) + { + /*******************************\ + * In all ili cases, note that * + * the resid is non-0 AND not * + * unchanged. * + \*******************************/ + xs->resid + = ntohl(*((long *)sense->ext.extended.info)); + if(xs->bp) + { + if(xs->resid < 0) + { /* never on block devices */ + /***********************\ + * it's only really bad * + * if we have lost data * + * (the record was * + * bigger than the read) * + \***********************/ + return(EIO); + } + } + } + else + { /* makes no sense.. complain */ + printf("BAD length error?"); + } + }/* there may be some other error. check the rest */ + + key=sense->ext.extended.sense_key; + switch(key) + { + case 0x0: + return(ESUCCESS); + case 0x1: + if(!silent) + { + printf("st%d: soft error(corrected) ", unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + else + { + printf("\n"); + } + } + return(ESUCCESS); + case 0x2: + if(!silent) printf("st%d: not ready\n ", unit); + return(ENODEV); + case 0x3: + if(!silent) + { + printf("st%d: medium error ", unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + else + { + printf("\n"); + } + } + return(EIO); + case 0x4: + if(!silent) printf("st%d: non-media hardware failure\n ", + unit); + return(EIO); + case 0x5: + if(!silent) printf("st%d: illegal request\n ", unit); + return(EINVAL); + case 0x6: + if(!silent) printf("st%d: Unit attention.\n ", unit); + st_data[unit].flags &= ~(ST_AT_FILEMARK|ST_AT_EOM); + st_info_valid[unit] = FALSE; + if (st_data[unit].flags & ST_OPEN) /* TEMP!!!! */ + return(EIO); + else + return(ESUCCESS); + case 0x7: + if(!silent) + { + printf("st%d: attempted protection violation " + , unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + else + { + printf("\n"); + } + } + return(EACCES); + case 0x8: + if(!silent) + { + printf("st%d: block wrong state (worm)\n " + , unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + else + { + printf("\n"); + } + } + return(EIO); + case 0x9: + if(!silent) printf("st%d: vendor unique\n", + unit); + return(EIO); + case 0xa: + if(!silent) printf("st%d: copy aborted\n ", + unit); + return(EIO); + case 0xb: + if(!silent) printf("st%d: command aborted\n ", + unit); + return(EIO); + case 0xc: + if(!silent) + { + printf("st%d: search returned\n ", unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + else + { + printf("\n"); + } + } + return(ESUCCESS); + case 0xd: + if(!silent) printf("st%d: volume overflow\n ", + unit); + return(ENOSPC); + case 0xe: + if(!silent) + { + printf("st%d: verify miscompare\n ", unit); + if(sense->valid) + { + printf("block no. %d (decimal)\n", + (sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); + } + else + { + printf("\n"); + } + } + return(EIO); + case 0xf: + if(!silent) printf("st%d: unknown error key\n ", + unit); + return(EIO); + } + break; + } + /***************************************************************\ + * If it's NOT class 7, just report it. * + \***************************************************************/ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + { + if(!silent) printf("st%d: error class %d code %d\n", + unit, + sense->error_class, + sense->error_code); + if(sense->valid) + if(!silent) printf("block no. %d (decimal)\n", + (sense->ext.unextended.blockhi <<16), + + (sense->ext.unextended.blockmed <<8), + + (sense->ext.unextended.blocklow )); + } + return(EIO); + } +} + +#if defined(OSF) + +stsize(dev_t dev) +{ + printf("stsize() -- not implemented\n"); + return(0); +} + +stdump() +{ + printf("stdump() -- not implemented\n"); + return(-1); +} + +#endif /* defined(OSF) */ + diff --git a/sys/sys/cdio.h b/sys/sys/cdio.h new file mode 100644 index 000000000000..0bd4ea774887 --- /dev/null +++ b/sys/sys/cdio.h @@ -0,0 +1,149 @@ +/* + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + */ +/* Shared between kernel & process */ + +struct cd_toc_entry { + u_char :8; + u_char control:4; + u_char addr_type:4; + u_char track; + u_char :8; + u_char addr[4]; +}; + +struct cd_sub_channel_header { + u_char :8; + u_char audio_status; +#define CD_AS_AUDIO_INVALID 0x00 +#define CD_AS_PLAY_IN_PROGRESS 0x11 +#define CD_AS_PLAY_PAUSED 0x12 +#define CD_AS_PLAY_COMPLETED 0x13 +#define CD_AS_PLAY_ERROR 0x14 +#define CD_AS_NO_STATUS 0x15 + u_char data_len[2]; +}; + +struct cd_sub_channel_position_data { + u_char data_format; + u_char control:4; + u_char addr_type:4; + u_char track_number; + u_char index_number; + u_char absaddr[4]; + u_char reladdr[4]; +}; + +struct cd_sub_channel_media_catalog { + u_char data_format; + u_char :8; + u_char :8; + u_char :8; + u_char :7; + u_char mc_valid:1; + u_char mc_number[15]; +}; + +struct cd_sub_channel_track_info { + u_char data_format; + u_char :8; + u_char track_number; + u_char :8; + u_char :7; + u_char ti_valid:1; + u_char ti_number[15]; +}; + +struct cd_sub_channel_info { + struct cd_sub_channel_header header; + union { + struct cd_sub_channel_position_data position; + struct cd_sub_channel_media_catalog media_catalog; + struct cd_sub_channel_track_info track_info; + } what; +}; + +/***************************************************************\ +* Ioctls for the CD drive * +\***************************************************************/ +struct ioc_play_track +{ + u_char start_track; + u_char start_index; + u_char end_track; + u_char end_index; +}; + +#define CDIOCPLAYTRACKS _IOW('c',1,struct ioc_play_track) +struct ioc_play_blocks +{ + int blk; + int len; +}; +#define CDIOCPLAYBLOCKS _IOW('c',2,struct ioc_play_blocks) + +struct ioc_read_subchannel { + u_char address_format; +#define CD_LBA_FORMAT 1 +#define CD_MSF_FORMAT 2 + u_char data_format; +#define CD_SUBQ_DATA 0 +#define CD_CURRENT_POSITION 1 +#define CD_MEDIA_CATALOG 2 +#define CD_TRACK_INFO 3 + u_char track; + int data_len; + struct cd_sub_channel_info *data; +}; +#define CDIOCREADSUBCHANNEL _IOWR('c', 3 , struct ioc_read_subchannel ) + + +struct ioc_toc_header { + u_short len; + u_char starting_track; + u_char ending_track; +}; + +#define CDIOREADTOCHEADER _IOR('c',4,struct ioc_toc_header) + +struct ioc_read_toc_entry { + u_char address_format; + u_char starting_track; + u_short data_len; + struct cd_toc_entry *data; +}; +#define CDIOREADTOCENTRYS _IOWR('c',5,struct ioc_read_toc_entry) + +struct ioc_patch +{ + u_char patch[4]; /* one for each channel */ +}; +#define CDIOCSETPATCH _IOW('c',9,struct ioc_patch) +struct ioc_vol +{ + u_char vol[4]; /* one for each channel */ +}; +#define CDIOCGETVOL _IOR('c',10,struct ioc_vol) +#define CDIOCSETVOL _IOW('c',11,struct ioc_vol) +#define CDIOCSETMONO _IO('c',12) +#define CDIOCSETSTERIO _IO('c',13) +#define CDIOCSETMUTE _IO('c',14) +#define CDIOCSETLEFT _IO('c',15) +#define CDIOCSETRIGHT _IO('c',16) +#define CDIOCSETDEBUG _IO('c',17) +#define CDIOCCLRDEBUG _IO('c',18) +#define CDIOCPAUSE _IO('c',19) +#define CDIOCRESUME _IO('c',20) +#define CDIOCRESET _IO('c',21) +#define CDIOCSTART _IO('c',22) +#define CDIOCSTOP _IO('c',23) +#define CDIOCEJECT _IO('c',24) + + + diff --git a/sys/sys/chio.h b/sys/sys/chio.h new file mode 100644 index 000000000000..532e6eed54dc --- /dev/null +++ b/sys/sys/chio.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1982, 1986 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. + * + * @(#)chio.h 7.6 (Berkeley) 2/5/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + */ + +/* This is a "convertet" mtio.h from 386BSD + Stefan Grefen grefen@goofy.zdv.uni-mainz.de + */ + +/* + * Structures and definitions for changer io control commands + */ +#ifndef _CHIO_H_ +#define _CHIO_H_ + +#define CH_INVERT 0x10000 +#define CH_ADDR_MASK 0xffff +struct chop { + short ch_op; /* operations defined below */ + short result; /* The result */ + union { + struct { + int chm; /* Transport element */ + int from; + int to; + } move; + struct { + int chm; /* Transport element */ + int to; + } position; + struct { + short chmo; /* Offset of first CHM */ + short chms; /* No. of CHM */ + short slots; /* No. of Storage Elements */ + short sloto; /* Offset of first SE */ + short imexs; /* No. of Import/Export Slots */ + short imexo; /* Offset of first IM/EX */ + short drives; /* No. of CTS */ + short driveo; /* Offset of first CTS */ + short rot; /* CHM can rotate */ + } getparam; + struct { + int type; +#define CH_CHM 1 +#define CH_STOR 2 +#define CH_IMEX 3 +#define CH_CTS 4 + int from; + struct { + u_char elema_1; + u_char elema_0; + u_char full:1; + u_char rsvd:1; + u_char except:1; + u_char :5; + u_char rsvd2; + union { + struct { + u_char add_sense_code; + u_char add_sense_code_qualifier; + } specs; + short add_sense; +/* WARINING LSB only */ +#define CH_CHOLDER 0x0290 /* Cartridge holder is missing */ +#define CH_STATUSQ 0x0390 /* Status is questionable */ +#define CH_CTS_CLOSED 0x0490 /* CTS door is closed */ + + } ch_add_sense; + u_char rsvd3[3]; + u_char :6; + u_char invert:1; + u_char svalid:1; + u_char source_1; + u_char source_0; + u_char rsvd4[4]; + } elem_data; + } get_elem_stat; + } u; +}; + +/* operations */ +#define CHMOVE 1 +#define CHPOSITION 2 +#define CHGETPARAM 3 +#define CHGETELEM 4 + + +/* Changer IO control command */ +#define CHIOOP _IOWR('c', 1, struct chop) /* do a mag tape op */ +#endif diff --git a/sys/sys/cons.h b/sys/sys/cons.h new file mode 100644 index 000000000000..b3c706433ade --- /dev/null +++ b/sys/sys/cons.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1991 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. + * + * 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. + * + * @(#)cons.h 7.2 (Berkeley) 5/9/91 + */ + + +struct consdev { + int (*cn_probe)(); /* probe hardware and fill in consdev info */ + int (*cn_init)(); /* turn on as console */ + int (*cn_getc)(); /* kernel getchar interface */ + int (*cn_putc)(); /* kernel putchar interface */ + struct tty *cn_tp; /* tty structure for console device */ + dev_t cn_dev; /* major/minor of device */ + short cn_pri; /* pecking order; the higher the better */ +}; + +/* values for cn_pri - reflect our policy for console selection */ +#define CN_DEAD 0 /* device doesn't exist */ +#define CN_NORMAL 1 /* device exists but is nothing special */ +#define CN_INTERNAL 2 /* "internal" bit-mapped display */ +#define CN_REMOTE 3 /* serial interface with remote bit set */ + +/* XXX */ +#define CONSMAJOR 0 + +#ifdef KERNEL +extern struct consdev constab[]; +extern struct consdev *cn_tab; +extern struct tty *cn_tty; +#endif diff --git a/sys/sys/rlist.h b/sys/sys/rlist.h new file mode 100644 index 000000000000..bd468b151658 --- /dev/null +++ b/sys/sys/rlist.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1992 William Jolitz. All rights reserved. + * Written by William Jolitz 1/92 + * + * Redistribution and use in source and binary forms are freely permitted + * provided that the above copyright notice and attribution and date of work + * and this paragraph are duplicated in all such forms. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Resource lists. + * + * Usage: + * rlist_free(&swapmap, 100, 200); add space to swapmap + * rlist_alloc(&swapmap, 100, &loc); obtain 100 sectors from swap + * $Header: /usr/bill/working/sys/sys/RCS/rlist.h,v 1.2 92/01/21 21:23:48 william Exp $ + */ + +/* A resource list element. */ +struct rlist { + unsigned rl_start; /* boundaries of extent - inclusive */ + unsigned rl_end; /* boundaries of extent - inclusive */ + struct rlist *rl_next; /* next list entry, if present */ +}; + +/* Functions to manipulate resource lists. */ +extern rlist_free __P((struct rlist **, unsigned, unsigned)); +int rlist_alloc __P((struct rlist **, unsigned, unsigned *)); +extern rlist_destroy __P((struct rlist **)); + + +/* heads of lists */ +struct rlist *swapmap; |