diff options
Diffstat (limited to 'sys/i386/i386')
-rw-r--r-- | sys/i386/i386/autoconf.c | 213 | ||||
-rw-r--r-- | sys/i386/i386/cons.c | 213 | ||||
-rw-r--r-- | sys/i386/i386/cons.h | 65 | ||||
-rw-r--r-- | sys/i386/i386/db_disasm.c | 1397 | ||||
-rw-r--r-- | sys/i386/i386/db_interface.c | 255 | ||||
-rw-r--r-- | sys/i386/i386/db_trace.c | 292 | ||||
-rw-r--r-- | sys/i386/i386/genassym.c | 174 | ||||
-rw-r--r-- | sys/i386/i386/in_cksum.c | 181 | ||||
-rw-r--r-- | sys/i386/i386/locore.s | 1830 | ||||
-rw-r--r-- | sys/i386/i386/machdep.c | 1131 | ||||
-rw-r--r-- | sys/i386/i386/math_emu.h | 154 | ||||
-rw-r--r-- | sys/i386/i386/math_emulate.c | 1487 | ||||
-rw-r--r-- | sys/i386/i386/mem.c | 191 | ||||
-rw-r--r-- | sys/i386/i386/microtime.s | 135 | ||||
-rw-r--r-- | sys/i386/i386/pmap.c | 1728 | ||||
-rw-r--r-- | sys/i386/i386/swapgeneric.c | 166 | ||||
-rw-r--r-- | sys/i386/i386/symbols.raw | 89 | ||||
-rw-r--r-- | sys/i386/i386/sys_machdep.c | 105 | ||||
-rw-r--r-- | sys/i386/i386/trap.c | 547 | ||||
-rw-r--r-- | sys/i386/i386/tsc.c | 271 | ||||
-rw-r--r-- | sys/i386/i386/vm_machdep.c | 410 |
21 files changed, 11034 insertions, 0 deletions
diff --git a/sys/i386/i386/autoconf.c b/sys/i386/i386/autoconf.c new file mode 100644 index 0000000..7eee991 --- /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/cons.c b/sys/i386/i386/cons.c new file mode 100644 index 0000000..6189d72 --- /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 0000000..b3c7064 --- /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 0000000..20430b6 --- /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 0000000..31e7849 --- /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 0000000..cbffbbc --- /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/genassym.c b/sys/i386/i386/genassym.c new file mode 100644 index 0000000..18ec37b --- /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 0000000..335dd35 --- /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 0000000..d558dba --- /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 0000000..f0351a7 --- /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 0000000..537fba5 --- /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 0000000..faf55a4 --- /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 0000000..650e21e --- /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 0000000..4af938b --- /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 0000000..66c7fec --- /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 0000000..0d76e72 --- /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 0000000..56e5ab4 --- /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 0000000..10b9ac2 --- /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 0000000..57195f3 --- /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 0000000..0fb7701 --- /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 0000000..27ef912 --- /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 */ +} |