summaryrefslogtreecommitdiff
path: root/i386/i386
diff options
context:
space:
mode:
authorThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
committerThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
commitf07a4c844da9f0ecae5bbee1ab94be56505f26f7 (patch)
tree12b07c7e578fc1a5f53dbfde2632408491ff2a70 /i386/i386
Initial source
Diffstat (limited to 'i386/i386')
-rw-r--r--i386/i386/ast.h47
-rw-r--r--i386/i386/ast_check.c61
-rw-r--r--i386/i386/ast_types.h36
-rw-r--r--i386/i386/cpu_number.h49
-rw-r--r--i386/i386/cswitch.S142
-rw-r--r--i386/i386/db_disasm.c1423
-rw-r--r--i386/i386/db_interface.c558
-rw-r--r--i386/i386/db_machdep.h110
-rw-r--r--i386/i386/db_trace.c674
-rw-r--r--i386/i386/debug.h72
-rw-r--r--i386/i386/debug_i386.c147
-rw-r--r--i386/i386/debug_trace.S55
-rw-r--r--i386/i386/eflags.h35
-rwxr-xr-xi386/i386/fpe.b478
-rw-r--r--i386/i386/fpe.b_elf576
-rw-r--r--i386/i386/fpe_linkage.c359
-rw-r--r--i386/i386/fpu.c750
-rw-r--r--i386/i386/fpu.h130
-rw-r--r--i386/i386/gdt.c88
-rw-r--r--i386/i386/gdt.h72
-rw-r--r--i386/i386/hardclock.c99
-rw-r--r--i386/i386/i386asm.sym139
-rw-r--r--i386/i386/idt-gen.h47
-rw-r--r--i386/i386/idt.c59
-rw-r--r--i386/i386/idt_inittab.S121
-rw-r--r--i386/i386/io_emulate.c108
-rw-r--r--i386/i386/io_emulate.h43
-rw-r--r--i386/i386/io_map.c58
-rw-r--r--i386/i386/io_port.h43
-rw-r--r--i386/i386/iopb.c615
-rw-r--r--i386/i386/iopb.h62
-rw-r--r--i386/i386/ipl.h77
-rw-r--r--i386/i386/ktss.c61
-rw-r--r--i386/i386/ktss.h30
-rw-r--r--i386/i386/kttd_interface.c577
-rw-r--r--i386/i386/kttd_machdep.h59
-rw-r--r--i386/i386/ldt.c64
-rw-r--r--i386/i386/ldt.h66
-rw-r--r--i386/i386/lock.h130
-rw-r--r--i386/i386/locore.S1726
-rw-r--r--i386/i386/loose_ends.c82
-rw-r--r--i386/i386/mach_i386.srv27
-rw-r--r--i386/i386/mach_param.h31
-rw-r--r--i386/i386/machine_routines.h37
-rw-r--r--i386/i386/machspl.h29
-rw-r--r--i386/i386/mp_desc.c235
-rw-r--r--i386/i386/mp_desc.h84
-rw-r--r--i386/i386/pcb.c769
-rw-r--r--i386/i386/phys.c102
-rw-r--r--i386/i386/pic.c270
-rw-r--r--i386/i386/pic.h197
-rw-r--r--i386/i386/pio.h61
-rw-r--r--i386/i386/pit.c236
-rw-r--r--i386/i386/pit.h118
-rw-r--r--i386/i386/pmap.h30
-rw-r--r--i386/i386/proc_reg.h150
-rw-r--r--i386/i386/sched_param.h40
-rw-r--r--i386/i386/seg.c5
-rw-r--r--i386/i386/seg.h184
-rw-r--r--i386/i386/setjmp.h36
-rw-r--r--i386/i386/spl.S220
-rw-r--r--i386/i386/spl.h51
-rw-r--r--i386/i386/thread.h195
-rw-r--r--i386/i386/time_stamp.h30
-rw-r--r--i386/i386/timer.h71
-rw-r--r--i386/i386/trap.c1139
-rw-r--r--i386/i386/trap.h38
-rw-r--r--i386/i386/tss.h76
-rw-r--r--i386/i386/user_ldt.c389
-rw-r--r--i386/i386/user_ldt.h55
-rw-r--r--i386/i386/vm_param.h64
-rw-r--r--i386/i386/vm_tuning.h35
-rw-r--r--i386/i386/xpr.h32
-rw-r--r--i386/i386/zalloc.h29
74 files changed, 15193 insertions, 0 deletions
diff --git a/i386/i386/ast.h b/i386/i386/ast.h
new file mode 100644
index 00000000..7afaa41a
--- /dev/null
+++ b/i386/i386/ast.h
@@ -0,0 +1,47 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_AST_H_
+#define _I386_AST_H_
+
+/*
+ * Machine-dependent AST file for machines with no hardware AST support.
+ *
+ * For the I386, we define AST_I386_FP to handle delayed
+ * floating-point exceptions. The FPU may interrupt on errors
+ * while the user is not running (in kernel or other thread running).
+ */
+
+#define AST_I386_FP 0x80000000
+
+#define MACHINE_AST_PER_THREAD AST_I386_FP
+
+
+/* Chain to the machine-independent header. */
+/* #include_next "ast.h" */
+
+
+#endif /* _I386_AST_H_ */
diff --git a/i386/i386/ast_check.c b/i386/i386/ast_check.c
new file mode 100644
index 00000000..faa3b8ed
--- /dev/null
+++ b/i386/i386/ast_check.c
@@ -0,0 +1,61 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <cpus.h>
+
+#if NCPUS > 1
+
+/*
+ * Handle signalling ASTs on other processors.
+ *
+ * Initial i386 implementation does nothing.
+ */
+
+#include <kern/processor.h>
+
+/*
+ * Initialize for remote invocation of ast_check.
+ */
+init_ast_check(processor)
+ processor_t processor;
+{
+#ifdef lint
+ processor++;
+#endif lint
+}
+
+/*
+ * Cause remote invocation of ast_check. Caller is at splsched().
+ */
+cause_ast_check(processor)
+ processor_t processor;
+{
+#ifdef lint
+ processor++;
+#endif lint
+}
+
+#endif /* NCPUS > 1 */
diff --git a/i386/i386/ast_types.h b/i386/i386/ast_types.h
new file mode 100644
index 00000000..89e31825
--- /dev/null
+++ b/i386/i386/ast_types.h
@@ -0,0 +1,36 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_AST_TYPES_H_
+#define _I386_AST_TYPES_H_
+
+/*
+ * Data type for remote ast_check() invocation support. Currently
+ * not implemented. Do this first to avoid include problems.
+ */
+typedef int ast_check_t;
+
+#endif /* _I386_AST_TYPES_H_ */
diff --git a/i386/i386/cpu_number.h b/i386/i386/cpu_number.h
new file mode 100644
index 00000000..e60ac771
--- /dev/null
+++ b/i386/i386/cpu_number.h
@@ -0,0 +1,49 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Machine-dependent definitions for cpu identification.
+ *
+ */
+#ifndef _I386_CPU_NUMBER_H_
+#define _I386_CPU_NUMBER_H_
+
+#if NCPUS > 1
+
+/* More-specific code must define cpu_number() and CPU_NUMBER. */
+#define CX(addr, reg) addr(,reg,4)
+
+#else /* NCPUS == 1 */
+
+#define CPU_NUMBER(reg)
+#define CX(addr,reg) addr
+
+#endif /* NCPUS == 1 */
+
+#ifndef ASSEMBLER
+#include "kern/cpu_number.h"
+#endif
+
+#endif /* _I386_CPU_NUMBER_H_ */
diff --git a/i386/i386/cswitch.S b/i386/i386/cswitch.S
new file mode 100644
index 00000000..8187980f
--- /dev/null
+++ b/i386/i386/cswitch.S
@@ -0,0 +1,142 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <cpus.h>
+#include <platforms.h>
+
+#include <mach/machine/asm.h>
+
+#include "proc_reg.h"
+#include "i386asm.h"
+#include "cpu_number.h"
+
+/*
+ * Context switch routines for i386.
+ */
+
+ENTRY(Load_context)
+ movl S_ARG0,%ecx /* get thread */
+ movl TH_KERNEL_STACK(%ecx),%ecx /* get kernel stack */
+ lea KERNEL_STACK_SIZE-IKS_SIZE-IEL_SIZE(%ecx),%edx
+ /* point to stack top */
+ CPU_NUMBER(%eax)
+ movl %ecx,CX(EXT(active_stacks),%eax) /* store stack address */
+ movl %edx,CX(EXT(kernel_stack),%eax) /* store stack top */
+
+ movl KSS_ESP(%ecx),%esp /* switch stacks */
+ movl KSS_ESI(%ecx),%esi /* restore registers */
+ movl KSS_EDI(%ecx),%edi
+ movl KSS_EBP(%ecx),%ebp
+ movl KSS_EBX(%ecx),%ebx
+ xorl %eax,%eax /* return zero (no old thread) */
+ jmp *KSS_EIP(%ecx) /* resume thread */
+
+/*
+ * This really only has to save registers
+ * when there is no explicit continuation.
+ */
+
+ENTRY(Switch_context)
+ CPU_NUMBER(%edx)
+ movl CX(EXT(active_stacks),%edx),%ecx /* get old kernel stack */
+
+ movl %ebx,KSS_EBX(%ecx) /* save registers */
+ movl %ebp,KSS_EBP(%ecx)
+ movl %edi,KSS_EDI(%ecx)
+ movl %esi,KSS_ESI(%ecx)
+ popl KSS_EIP(%ecx) /* save return PC */
+ movl %esp,KSS_ESP(%ecx) /* save SP */
+
+ movl 0(%esp),%eax /* get old thread */
+ movl %ecx,TH_KERNEL_STACK(%eax) /* save old stack */
+ movl 4(%esp),%ebx /* get continuation */
+ movl %ebx,TH_SWAP_FUNC(%eax) /* save continuation */
+
+ movl 8(%esp),%esi /* get new thread */
+
+ movl TH_KERNEL_STACK(%esi),%ecx /* get its kernel stack */
+ lea KERNEL_STACK_SIZE-IKS_SIZE-IEL_SIZE(%ecx),%ebx
+ /* point to stack top */
+
+ movl %esi,CX(EXT(active_threads),%edx) /* new thread is active */
+ movl %ecx,CX(EXT(active_stacks),%edx) /* set current stack */
+ movl %ebx,CX(EXT(kernel_stack),%edx) /* set stack top */
+
+ movl KSS_ESP(%ecx),%esp /* switch stacks */
+ movl KSS_ESI(%ecx),%esi /* restore registers */
+ movl KSS_EDI(%ecx),%edi
+ movl KSS_EBP(%ecx),%ebp
+ movl KSS_EBX(%ecx),%ebx
+ jmp *KSS_EIP(%ecx) /* return old thread */
+
+ENTRY(Thread_continue)
+ pushl %eax /* push the thread argument */
+ xorl %ebp,%ebp /* zero frame pointer */
+ call *%ebx /* call real continuation */
+
+#if NCPUS > 1
+/*
+ * void switch_to_shutdown_context(thread_t thread,
+ * void (*routine)(processor_t),
+ * processor_t processor)
+ *
+ * saves the kernel context of the thread,
+ * switches to the interrupt stack,
+ * continues the thread (with thread_continue),
+ * then runs routine on the interrupt stack.
+ *
+ * Assumes that the thread is a kernel thread (thus
+ * has no FPU state)
+ */
+ENTRY(switch_to_shutdown_context)
+ CPU_NUMBER(%edx)
+ movl EXT(active_stacks)(,%edx,4),%ecx /* get old kernel stack */
+ movl %ebx,KSS_EBX(%ecx) /* save registers */
+ movl %ebp,KSS_EBP(%ecx)
+ movl %edi,KSS_EDI(%ecx)
+ movl %esi,KSS_ESI(%ecx)
+ popl KSS_EIP(%ecx) /* save return PC */
+ movl %esp,KSS_ESP(%ecx) /* save SP */
+
+ movl 0(%esp),%eax /* get old thread */
+ movl %ecx,TH_KERNEL_STACK(%eax) /* save old stack */
+ movl $0,TH_SWAP_FUNC(%eax) /* clear continuation */
+ movl 4(%esp),%ebx /* get routine to run next */
+ movl 8(%esp),%esi /* get its argument */
+
+ movl _interrupt_stack(,%edx,4),%ecx /* point to its interrupt stack */
+ lea INTSTACK_SIZE(%ecx),%esp /* switch to it (top) */
+
+ pushl %eax /* push thread */
+ call EXT(thread_dispatch) /* reschedule thread */
+ addl $4,%esp /* clean stack */
+
+ pushl %esi /* push argument */
+ call *%ebx /* call routine to run */
+ hlt /* (should never return) */
+
+#endif NCPUS > 1
+
diff --git a/i386/i386/db_disasm.c b/i386/i386/db_disasm.c
new file mode 100644
index 00000000..dfb85e2c
--- /dev/null
+++ b/i386/i386/db_disasm.c
@@ -0,0 +1,1423 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1994,1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+#include "mach_kdb.h"
+#if MACH_KDB
+
+/*
+ * Instruction disassembler.
+ */
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+
+#include <ddb/db_access.h>
+#include <ddb/db_output.h>
+#include <ddb/db_sym.h>
+
+#include <kern/task.h>
+
+/*
+ * Switch to disassemble 16-bit code.
+ */
+boolean_t db_disasm_16 = FALSE;
+
+/*
+ * 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 El 3 /* address, long size */
+#define Ew 4 /* address, word size */
+#define Eb 5 /* address, byte size */
+#define R 6 /* register, in 'reg' field */
+#define Rw 7 /* word register, in 'reg' field */
+#define Ri 8 /* register in instruction */
+#define S 9 /* segment reg, in 'reg' field */
+#define Si 10 /* segment reg, in instruction */
+#define A 11 /* accumulator */
+#define BX 12 /* (bx) */
+#define CL 13 /* cl, for shifts */
+#define DX 14 /* dx, for IO */
+#define SI 15 /* si */
+#define DI 16 /* di */
+#define CR 17 /* control register */
+#define DR 18 /* debug register */
+#define TR 19 /* test register */
+#define I 20 /* immediate, unsigned */
+#define Is 21 /* immediate, signed */
+#define Ib 22 /* byte immediate, unsigned */
+#define Ibs 23 /* byte immediate, signed */
+#define Iw 24 /* word immediate, unsigned */
+#define Il 25 /* long immediate */
+#define O 26 /* direct address */
+#define Db 27 /* byte displacement from EIP */
+#define Dl 28 /* long displacement from EIP */
+#define o1 29 /* constant 1 */
+#define o3 30 /* constant 3 */
+#define OS 31 /* immediate offset/segment */
+#define ST 32 /* FP stack top */
+#define STI 33 /* FP stack */
+#define X 34 /* extended FP op */
+#define XA 35 /* 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,El), 0 }, /* use El for reg */
+/*21*/ { "mov", TRUE, LONG, op2(DR,El), 0 }, /* since mod == 11 */
+/*22*/ { "mov", TRUE, LONG, op2(El,CR), 0 },
+/*23*/ { "mov", TRUE, LONG, op2(El,DR), 0 },
+/*24*/ { "mov", TRUE, LONG, op2(TR,El), 0 },
+/*25*/ { "", FALSE, NONE, 0, 0 },
+/*26*/ { "mov", TRUE, LONG, op2(El,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(R,E), 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(R,E), 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*/ { "btr", 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(Eb,R), 0 },
+/*b7*/ { "movzw", TRUE, LONG, op2(Ew,R), 0 },
+
+/*b8*/ { "", FALSE, NONE, 0, 0 },
+/*b9*/ { "", FALSE, NONE, 0, 0 },
+/*ba*/ { "", TRUE, LONG, op2(Ibs,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(Eb,R), 0 },
+/*bf*/ { "movsw", TRUE, LONG, op2(Ew,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*/ { "lods", FALSE, BYTE, op1(SI), 0 },
+/*ad*/ { "lods", FALSE, LONG, op1(SI), 0 },
+/*ae*/ { "scas", FALSE, BYTE, op1(DI), 0 },
+/*af*/ { "scas", FALSE, LONG, op1(DI), 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, task) \
+ result = db_get_task_value((loc), (size), (is_signed), (task)); \
+ (loc) += (size);
+
+/*
+ * Read address at location and return updated location.
+ */
+db_addr_t
+db_read_address(
+ db_addr_t loc,
+ int short_addr,
+ int regmodrm,
+ struct i_addr *addrp, /* out */
+ task_t task)
+{
+ int mod, rm, sib, index, 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, task);
+ 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, task);
+ addrp->disp = disp;
+ addrp->base = db_index_reg_16[rm];
+ break;
+ case 2:
+ get_value_inc(disp, loc, 2, TRUE, task);
+ addrp->disp = disp;
+ addrp->base = db_index_reg_16[rm];
+ break;
+ }
+ }
+ else {
+ if (mod != 3 && rm == 4) {
+ get_value_inc(sib, loc, 1, FALSE, task);
+ 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, task);
+ addrp->base = 0;
+ }
+ else {
+ addrp->disp = 0;
+ addrp->base = db_reg[LONG][rm];
+ }
+ break;
+
+ case 1:
+ get_value_inc(disp, loc, 1, TRUE, task);
+ addrp->disp = disp;
+ addrp->base = db_reg[LONG][rm];
+ break;
+
+ case 2:
+ get_value_inc(disp, loc, 4, FALSE, task);
+ addrp->disp = disp;
+ addrp->base = db_reg[LONG][rm];
+ break;
+ }
+ }
+ return loc;
+}
+
+void
+db_print_address(
+ char * seg,
+ int size,
+ struct i_addr *addrp,
+ task_t task)
+{
+ if (addrp->is_reg) {
+ db_printf("%s", db_reg[size][addrp->disp]);
+ return;
+ }
+
+ if (seg) {
+ db_printf("%s:", seg);
+ }
+
+ if (addrp->base != 0 || addrp->index != 0) {
+ db_printf("%#n", addrp->disp);
+ db_printf("(");
+ if (addrp->base)
+ db_printf("%s", addrp->base);
+ if (addrp->index)
+ db_printf(",%s,%d", addrp->index, 1<<addrp->ss);
+ db_printf(")");
+ } else
+ db_task_printsym((db_addr_t)addrp->disp, DB_STGY_ANY, task);
+}
+
+/*
+ * Disassemble floating-point ("escape") instruction
+ * and return updated location.
+ */
+db_addr_t
+db_disasm_esc(
+ db_addr_t loc,
+ int inst,
+ int short_addr,
+ int size,
+ char * seg,
+ task_t task)
+{
+ int regmodrm;
+ struct finst *fp;
+ int mod;
+ struct i_addr address;
+ char * name;
+
+ get_value_inc(regmodrm, loc, 1, FALSE, task);
+ 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, task);
+ 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, task);
+ }
+ 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(
+ db_addr_t loc,
+ boolean_t altfmt,
+ task_t task)
+{
+ 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, task);
+ if (db_disasm_16) {
+ short_addr = TRUE;
+ size = WORD;
+ }
+ else {
+ short_addr = FALSE;
+ size = LONG;
+ }
+ seg = 0;
+ regmodrm = 0;
+
+ /*
+ * Get prefixes
+ */
+ prefix = TRUE;
+ do {
+ switch (inst) {
+ case 0x66: /* data16 */
+ if (size == LONG)
+ size = WORD;
+ else
+ size = LONG;
+ break;
+ case 0x67:
+ short_addr = !short_addr;
+ 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, task);
+ }
+ } while (prefix);
+
+ if (inst >= 0xd8 && inst <= 0xdf) {
+ loc = db_disasm_esc(loc, inst, short_addr, size, seg, task);
+ db_printf("\n");
+ return loc;
+ }
+
+ if (inst == 0x0f) {
+ get_value_inc(inst, loc, 1, FALSE, task);
+ 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, task);
+ loc = db_read_address(loc, short_addr, regmodrm, &address, task);
+ }
+
+ 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, task);
+ break;
+
+ case Eind:
+ db_printf("*");
+ db_print_address(seg, size, &address, task);
+ break;
+
+ case El:
+ db_print_address(seg, LONG, &address, task);
+ break;
+
+ case Ew:
+ db_print_address(seg, WORD, &address, task);
+ break;
+
+ case Eb:
+ db_print_address(seg, BYTE, &address, task);
+ 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, task);/* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Is:
+ len = db_lengths[size];
+ get_value_inc(imm, loc, len, TRUE, task); /* signed */
+ db_printf("$%#r", imm);
+ break;
+
+ case Ib:
+ get_value_inc(imm, loc, 1, FALSE, task); /* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Ibs:
+ get_value_inc(imm, loc, 1, TRUE, task); /* signed */
+ db_printf("$%#r", imm);
+ break;
+
+ case Iw:
+ get_value_inc(imm, loc, 2, FALSE, task); /* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Il:
+ get_value_inc(imm, loc, 4, FALSE, task);
+ db_printf("$%#n", imm);
+ break;
+
+ case O:
+ if (short_addr) {
+ get_value_inc(displ, loc, 2, TRUE, task);
+ }
+ else {
+ get_value_inc(displ, loc, 4, TRUE, task);
+ }
+ if (seg)
+ db_printf("%s:%#r",seg, displ);
+ else
+ db_task_printsym((db_addr_t)displ, DB_STGY_ANY, task);
+ break;
+
+ case Db:
+ get_value_inc(displ, loc, 1, TRUE, task);
+ if (short_addr) {
+ /* offset only affects low 16 bits */
+ displ = (loc & 0xffff0000)
+ | ((loc + displ) & 0xffff);
+ }
+ else
+ displ = displ + loc;
+ db_task_printsym((db_addr_t)displ,DB_STGY_XTRN,task);
+ break;
+
+ case Dl:
+ if (short_addr) {
+ get_value_inc(displ, loc, 2, TRUE, task);
+ /* offset only affects low 16 bits */
+ displ = (loc & 0xffff0000)
+ | ((loc + displ) & 0xffff);
+ }
+ else {
+ get_value_inc(displ, loc, 4, TRUE, task);
+ displ = displ + loc;
+ }
+ db_task_printsym((db_addr_t)displ, DB_STGY_XTRN, task);
+ break;
+
+ case o1:
+ db_printf("$1");
+ break;
+
+ case o3:
+ db_printf("$3");
+ break;
+
+ case OS:
+ if (short_addr) {
+ get_value_inc(imm, loc, 2, FALSE, task); /* offset */
+ }
+ else {
+ get_value_inc(imm, loc, 4, FALSE, task); /* offset */
+ }
+ get_value_inc(imm2, loc, 2, FALSE, task); /* segment */
+ db_printf("$%#n,%#n", imm2, imm);
+ break;
+ }
+ }
+
+ if (altfmt == 0 && !db_disasm_16) {
+ if (inst == 0xe9 || inst == 0xeb) {
+ /*
+ * GAS pads to longword boundary after unconditional jumps.
+ */
+ loc = (loc + (4-1)) & ~(4-1);
+ }
+ }
+ db_printf("\n");
+ return loc;
+}
+
+#endif MACH_KDB
diff --git a/i386/i386/db_interface.c b/i386/i386/db_interface.c
new file mode 100644
index 00000000..30b0b0f3
--- /dev/null
+++ b/i386/i386/db_interface.c
@@ -0,0 +1,558 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Interface to new debugger.
+ */
+
+#include "mach_kdb.h"
+#if MACH_KDB
+
+#include <cpus.h>
+
+#include <sys/reboot.h>
+#include <vm/pmap.h>
+
+#include <i386/thread.h>
+#include <i386/db_machdep.h>
+#include <i386/seg.h>
+#include <i386/trap.h>
+#include <i386/setjmp.h>
+#include <i386/pmap.h>
+#include "gdt.h"
+#include "trap.h"
+
+#include "vm_param.h"
+#include <vm/vm_map.h>
+#include <kern/cpu_number.h>
+#include <kern/thread.h>
+#include <kern/task.h>
+#include <ddb/db_task_thread.h>
+#include <machine/machspl.h>
+
+struct i386_saved_state *i386_last_saved_statep;
+struct i386_saved_state i386_nested_saved_state;
+unsigned i386_last_kdb_sp;
+
+extern thread_t db_default_thread;
+
+/*
+ * Print trap reason.
+ */
+kdbprinttrap(type, code)
+ int type, code;
+{
+ printf("kernel: %s (%d), code=%x\n",
+ trap_name(type), type, code);
+}
+
+/*
+ * kdb_trap - field a TRACE or BPT trap
+ */
+
+extern jmp_buf_t *db_recover;
+spl_t saved_ipl[NCPUS]; /* just to know what was IPL before trap */
+
+boolean_t
+kdb_trap(
+ int type,
+ int code,
+ register struct i386_saved_state *regs)
+{
+ spl_t s;
+
+ s = splhigh();
+ saved_ipl[cpu_number()] = s;
+
+ switch (type) {
+ case T_DEBUG: /* single_step */
+ {
+ extern int dr_addr[];
+ int addr;
+ int status = dr6();
+
+ if (status & 0xf) { /* hmm hdw break */
+ addr = status & 0x8 ? dr_addr[3] :
+ status & 0x4 ? dr_addr[2] :
+ status & 0x2 ? dr_addr[1] :
+ dr_addr[0];
+ regs->efl |= EFL_RF;
+ db_single_step_cmd(addr, 0, 1, "p");
+ }
+ }
+ case T_INT3: /* breakpoint */
+ case T_WATCHPOINT: /* watchpoint */
+ case -1: /* keyboard interrupt */
+ break;
+
+ default:
+ if (db_recover) {
+ i386_nested_saved_state = *regs;
+ db_printf("Caught %s (%d), code = %x, pc = %x\n",
+ trap_name(type), type, code, regs->eip);
+ db_error("");
+ /*NOTREACHED*/
+ }
+ kdbprinttrap(type, code);
+ }
+
+#if NCPUS > 1
+ if (db_enter())
+#endif /* NCPUS > 1 */
+ {
+ i386_last_saved_statep = regs;
+ i386_last_kdb_sp = (unsigned) &type;
+
+ /* XXX Should switch to ddb`s own stack here. */
+
+ ddb_regs = *regs;
+ if ((regs->cs & 0x3) == 0) {
+ /*
+ * Kernel mode - esp and ss not saved
+ */
+ ddb_regs.uesp = (int)&regs->uesp; /* kernel stack pointer */
+ ddb_regs.ss = KERNEL_DS;
+ }
+
+ cnpollc(TRUE);
+ db_task_trap(type, code, (regs->cs & 0x3) != 0);
+ cnpollc(FALSE);
+
+ regs->eip = ddb_regs.eip;
+ regs->efl = ddb_regs.efl;
+ regs->eax = ddb_regs.eax;
+ regs->ecx = ddb_regs.ecx;
+ regs->edx = ddb_regs.edx;
+ regs->ebx = ddb_regs.ebx;
+ if (regs->cs & 0x3) {
+ /*
+ * user mode - saved esp and ss valid
+ */
+ regs->uesp = ddb_regs.uesp; /* user stack pointer */
+ regs->ss = ddb_regs.ss & 0xffff; /* user stack segment */
+ }
+ regs->ebp = ddb_regs.ebp;
+ regs->esi = ddb_regs.esi;
+ regs->edi = ddb_regs.edi;
+ regs->es = ddb_regs.es & 0xffff;
+ regs->cs = ddb_regs.cs & 0xffff;
+ regs->ds = ddb_regs.ds & 0xffff;
+ regs->fs = ddb_regs.fs & 0xffff;
+ regs->gs = ddb_regs.gs & 0xffff;
+
+ if ((type == T_INT3) &&
+ (db_get_task_value(regs->eip, BKPT_SIZE, FALSE, TASK_NULL)
+ == BKPT_INST))
+ regs->eip += BKPT_SIZE;
+ }
+#if NCPUS > 1
+ db_leave();
+#endif /* NCPUS > 1 */
+
+ splx(s);
+ return 1;
+}
+
+/*
+ * Enter KDB through a keyboard trap.
+ * We show the registers as of the keyboard interrupt
+ * instead of those at its call to KDB.
+ */
+struct int_regs {
+ int gs;
+ int fs;
+ int edi;
+ int esi;
+ int ebp;
+ int ebx;
+ struct i386_interrupt_state *is;
+};
+
+void
+kdb_kentry(
+ struct int_regs *int_regs)
+{
+ struct i386_interrupt_state *is = int_regs->is;
+ spl_t s = splhigh();
+
+#if NCPUS > 1
+ if (db_enter())
+#endif /* NCPUS > 1 */
+ {
+ if (is->cs & 0x3) {
+ ddb_regs.uesp = ((int *)(is+1))[0];
+ ddb_regs.ss = ((int *)(is+1))[1];
+ }
+ else {
+ ddb_regs.ss = KERNEL_DS;
+ ddb_regs.uesp= (int)(is+1);
+ }
+ ddb_regs.efl = is->efl;
+ ddb_regs.cs = is->cs;
+ ddb_regs.eip = is->eip;
+ ddb_regs.eax = is->eax;
+ ddb_regs.ecx = is->ecx;
+ ddb_regs.edx = is->edx;
+ ddb_regs.ebx = int_regs->ebx;
+ ddb_regs.ebp = int_regs->ebp;
+ ddb_regs.esi = int_regs->esi;
+ ddb_regs.edi = int_regs->edi;
+ ddb_regs.ds = is->ds;
+ ddb_regs.es = is->es;
+ ddb_regs.fs = int_regs->fs;
+ ddb_regs.gs = int_regs->gs;
+
+ cnpollc(TRUE);
+ db_task_trap(-1, 0, (ddb_regs.cs & 0x3) != 0);
+ cnpollc(FALSE);
+
+ if (ddb_regs.cs & 0x3) {
+ ((int *)(is+1))[0] = ddb_regs.uesp;
+ ((int *)(is+1))[1] = ddb_regs.ss & 0xffff;
+ }
+ is->efl = ddb_regs.efl;
+ is->cs = ddb_regs.cs & 0xffff;
+ is->eip = ddb_regs.eip;
+ is->eax = ddb_regs.eax;
+ is->ecx = ddb_regs.ecx;
+ is->edx = ddb_regs.edx;
+ int_regs->ebx = ddb_regs.ebx;
+ int_regs->ebp = ddb_regs.ebp;
+ int_regs->esi = ddb_regs.esi;
+ int_regs->edi = ddb_regs.edi;
+ is->ds = ddb_regs.ds & 0xffff;
+ is->es = ddb_regs.es & 0xffff;
+ int_regs->fs = ddb_regs.fs & 0xffff;
+ int_regs->gs = ddb_regs.gs & 0xffff;
+ }
+#if NCPUS > 1
+ db_leave();
+#endif /* NCPUS > 1 */
+
+ (void) splx(s);
+}
+
+boolean_t db_no_vm_fault = TRUE;
+
+int
+db_user_to_kernel_address(
+ task_t task,
+ vm_offset_t addr,
+ unsigned *kaddr,
+ int flag)
+{
+ register pt_entry_t *ptp;
+ boolean_t faulted = FALSE;
+
+ retry:
+ ptp = pmap_pte(task->map->pmap, addr);
+ if (ptp == PT_ENTRY_NULL || (*ptp & INTEL_PTE_VALID) == 0) {
+ if (!faulted && !db_no_vm_fault) {
+ kern_return_t err;
+
+ faulted = TRUE;
+ err = vm_fault( task->map,
+ trunc_page(addr),
+ VM_PROT_READ,
+ FALSE, FALSE, 0);
+ if (err == KERN_SUCCESS)
+ goto retry;
+ }
+ if (flag) {
+ db_printf("\nno memory is assigned to address %08x\n", addr);
+ db_error(0);
+ /* NOTREACHED */
+ }
+ return(-1);
+ }
+ *kaddr = (unsigned)ptetokv(*ptp) + (addr & (INTEL_PGBYTES-1));
+ return(0);
+}
+
+/*
+ * Read bytes from kernel address space for debugger.
+ */
+
+void
+db_read_bytes(
+ vm_offset_t addr,
+ register int size,
+ register char *data,
+ task_t task)
+{
+ register char *src;
+ register int n;
+ unsigned kern_addr;
+
+ src = (char *)addr;
+ if (addr >= VM_MIN_KERNEL_ADDRESS || task == TASK_NULL) {
+ if (task == TASK_NULL)
+ task = db_current_task();
+ while (--size >= 0) {
+ if (addr++ < VM_MIN_KERNEL_ADDRESS && task == TASK_NULL) {
+ db_printf("\nbad address %x\n", addr);
+ db_error(0);
+ /* NOTREACHED */
+ }
+ *data++ = *src++;
+ }
+ return;
+ }
+ while (size > 0) {
+ if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0)
+ return;
+ src = (char *)kern_addr;
+ n = intel_trunc_page(addr+INTEL_PGBYTES) - addr;
+ if (n > size)
+ n = size;
+ size -= n;
+ addr += n;
+ while (--n >= 0)
+ *data++ = *src++;
+ }
+}
+
+/*
+ * Write bytes to kernel address space for debugger.
+ */
+void
+db_write_bytes(
+ vm_offset_t addr,
+ register int size,
+ register char *data,
+ task_t task)
+{
+ 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;
+ void db_write_bytes_user_space();
+
+ if ((addr < VM_MIN_KERNEL_ADDRESS) ^
+ ((addr + size) <= VM_MIN_KERNEL_ADDRESS)) {
+ db_error("\ncannot write data into mixed space\n");
+ /* NOTREACHED */
+ }
+ if (addr < VM_MIN_KERNEL_ADDRESS) {
+ if (task) {
+ db_write_bytes_user_space(addr, size, data, task);
+ return;
+ } else if (db_current_task() == TASK_NULL) {
+ db_printf("\nbad address %x\n", addr);
+ db_error(0);
+ /* NOTREACHED */
+ }
+ }
+
+ if (addr >= VM_MIN_KERNEL_ADDRESS &&
+ addr <= (vm_offset_t)&etext)
+ {
+ ptep0 = pmap_pte(kernel_pmap, addr);
+ oldmap0 = *ptep0;
+ *ptep0 |= INTEL_PTE_WRITE;
+
+ 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;
+ *ptep1 |= INTEL_PTE_WRITE;
+ }
+ flush_tlb();
+ }
+
+ dst = (char *)addr;
+
+ while (--size >= 0)
+ *dst++ = *data++;
+
+ if (ptep0) {
+ *ptep0 = oldmap0;
+ if (ptep1) {
+ *ptep1 = oldmap1;
+ }
+ flush_tlb();
+ }
+}
+
+void
+db_write_bytes_user_space(
+ vm_offset_t addr,
+ register int size,
+ register char *data,
+ task_t task)
+{
+ register char *dst;
+ register int n;
+ unsigned kern_addr;
+
+ while (size > 0) {
+ if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0)
+ return;
+ dst = (char *)kern_addr;
+ n = intel_trunc_page(addr+INTEL_PGBYTES) - addr;
+ if (n > size)
+ n = size;
+ size -= n;
+ addr += n;
+ while (--n >= 0)
+ *dst++ = *data++;
+ }
+}
+
+boolean_t
+db_check_access(
+ vm_offset_t addr,
+ register int size,
+ task_t task)
+{
+ register n;
+ vm_offset_t kern_addr;
+
+ if (addr >= VM_MIN_KERNEL_ADDRESS) {
+ if (kernel_task == TASK_NULL)
+ return TRUE;
+ task = kernel_task;
+ } else if (task == TASK_NULL) {
+ if (current_thread() == THREAD_NULL)
+ return FALSE;
+ task = current_thread()->task;
+ }
+ while (size > 0) {
+ if (db_user_to_kernel_address(task, addr, &kern_addr, 0) < 0)
+ return FALSE;
+ n = intel_trunc_page(addr+INTEL_PGBYTES) - addr;
+ if (n > size)
+ n = size;
+ size -= n;
+ addr += n;
+ }
+ return TRUE;
+}
+
+boolean_t
+db_phys_eq(
+ task_t task1,
+ vm_offset_t addr1,
+ task_t task2,
+ vm_offset_t addr2)
+{
+ vm_offset_t kern_addr1, kern_addr2;
+
+ if (addr1 >= VM_MIN_KERNEL_ADDRESS || addr2 >= VM_MIN_KERNEL_ADDRESS)
+ return FALSE;
+ if ((addr1 & (INTEL_PGBYTES-1)) != (addr2 & (INTEL_PGBYTES-1)))
+ return FALSE;
+ if (task1 == TASK_NULL) {
+ if (current_thread() == THREAD_NULL)
+ return FALSE;
+ task1 = current_thread()->task;
+ }
+ if (db_user_to_kernel_address(task1, addr1, &kern_addr1, 0) < 0
+ || db_user_to_kernel_address(task2, addr2, &kern_addr2, 0) < 0)
+ return FALSE;
+ return(kern_addr1 == kern_addr2);
+}
+
+#define DB_USER_STACK_ADDR (VM_MIN_KERNEL_ADDRESS)
+#define DB_NAME_SEARCH_LIMIT (DB_USER_STACK_ADDR-(INTEL_PGBYTES*3))
+
+static boolean_t
+db_search_null(
+ task_t task,
+ vm_offset_t *svaddr,
+ vm_offset_t evaddr,
+ vm_offset_t *skaddr,
+ int flag)
+{
+ register unsigned vaddr;
+ register unsigned *kaddr;
+
+ kaddr = (unsigned *)*skaddr;
+ for (vaddr = *svaddr; vaddr > evaddr; vaddr -= sizeof(unsigned)) {
+ if (vaddr % INTEL_PGBYTES == 0) {
+ vaddr -= sizeof(unsigned);
+ if (db_user_to_kernel_address(task, vaddr, skaddr, 0) < 0)
+ return FALSE;
+ kaddr = (vm_offset_t *)*skaddr;
+ } else {
+ vaddr -= sizeof(unsigned);
+ kaddr--;
+ }
+ if ((*kaddr == 0) ^ (flag == 0)) {
+ *svaddr = vaddr;
+ *skaddr = (unsigned)kaddr;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void
+db_task_name(
+ task_t task)
+{
+ register char *p;
+ register n;
+ unsigned vaddr, kaddr;
+
+ vaddr = DB_USER_STACK_ADDR;
+ kaddr = 0;
+
+ /*
+ * skip nulls at the end
+ */
+ if (!db_search_null(task, &vaddr, DB_NAME_SEARCH_LIMIT, &kaddr, 0)) {
+ db_printf(DB_NULL_TASK_NAME);
+ return;
+ }
+ /*
+ * search start of args
+ */
+ if (!db_search_null(task, &vaddr, DB_NAME_SEARCH_LIMIT, &kaddr, 1)) {
+ db_printf(DB_NULL_TASK_NAME);
+ return;
+ }
+
+ n = DB_TASK_NAME_LEN-1;
+ p = (char *)kaddr + sizeof(unsigned);
+ for (vaddr += sizeof(int); vaddr < DB_USER_STACK_ADDR && n > 0;
+ vaddr++, p++, n--) {
+ if (vaddr % INTEL_PGBYTES == 0) {
+ (void)db_user_to_kernel_address(task, vaddr, &kaddr, 0);
+ p = (char*)kaddr;
+ }
+ db_printf("%c", (*p < ' ' || *p > '~')? ' ': *p);
+ }
+ while (n-- >= 0) /* compare with >= 0 for one more space */
+ db_printf(" ");
+}
+
+#endif MACH_KDB
diff --git a/i386/i386/db_machdep.h b/i386/i386/db_machdep.h
new file mode 100644
index 00000000..ee5853a0
--- /dev/null
+++ b/i386/i386/db_machdep.h
@@ -0,0 +1,110 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_DB_MACHDEP_H_
+#define _I386_DB_MACHDEP_H_
+
+/*
+ * Machine-dependent defines for new kernel debugger.
+ */
+
+#include <mach/machine/vm_types.h>
+#include <mach/machine/vm_param.h>
+#include <mach/machine/eflags.h>
+#include <i386/thread.h> /* for thread_status */
+#include <i386/trap.h>
+
+typedef vm_offset_t db_addr_t; /* address - unsigned */
+typedef int db_expr_t; /* expression - signed */
+
+typedef struct i386_saved_state db_regs_t;
+db_regs_t ddb_regs; /* register state */
+#define DDB_REGS (&ddb_regs)
+#define SAVE_DDB_REGS DB_SAVE(db_regs_t, ddb_regs)
+#define RESTORE_DDB_REGS DB_RESTORE(ddb_regs)
+
+#define PC_REGS(regs) ((db_addr_t)(regs)->eip)
+
+#define BKPT_INST 0xcc /* breakpoint instruction */
+#define BKPT_SIZE (1) /* size of breakpoint inst */
+#define BKPT_SET(inst) (BKPT_INST)
+
+#define FIXUP_PC_AFTER_BREAK ddb_regs.eip -= 1;
+
+#define db_clear_single_step(regs) ((regs)->efl &= ~EFL_TF)
+#define db_set_single_step(regs) ((regs)->efl |= EFL_TF)
+
+#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_INT3)
+#define IS_WATCHPOINT_TRAP(type, code) ((type) == T_WATCHPOINT)
+
+#define I_CALL 0xe8
+#define I_CALLI 0xff
+#define I_RET 0xc3
+#define I_IRET 0xcf
+
+#define inst_trap_return(ins) (((ins)&0xff) == I_IRET)
+#define inst_return(ins) (((ins)&0xff) == I_RET)
+#define inst_call(ins) (((ins)&0xff) == I_CALL || \
+ (((ins)&0xff) == I_CALLI && \
+ ((ins)&0x3800) == 0x1000))
+#define inst_load(ins) 0
+#define inst_store(ins) 0
+
+/* access capability and access macros */
+
+#define DB_ACCESS_LEVEL 2 /* access any space */
+#define DB_CHECK_ACCESS(addr,size,task) \
+ db_check_access(addr,size,task)
+#define DB_PHYS_EQ(task1,addr1,task2,addr2) \
+ db_phys_eq(task1,addr1,task2,addr2)
+#define DB_VALID_KERN_ADDR(addr) \
+ ((addr) >= VM_MIN_KERNEL_ADDRESS && \
+ (addr) < VM_MAX_KERNEL_ADDRESS)
+#define DB_VALID_ADDRESS(addr,user) \
+ ((!(user) && DB_VALID_KERN_ADDR(addr)) || \
+ ((user) && (addr) < VM_MIN_KERNEL_ADDRESS))
+
+boolean_t db_check_access(/* vm_offset_t, int, task_t */);
+boolean_t db_phys_eq(/* task_t, vm_offset_t, task_t, vm_offset_t */);
+
+/* macros for printing OS server dependent task name */
+
+#define DB_TASK_NAME(task) db_task_name(task)
+#define DB_TASK_NAME_TITLE "COMMAND "
+#define DB_TASK_NAME_LEN 23
+#define DB_NULL_TASK_NAME "? "
+
+void db_task_name(/* task_t */);
+
+/* macro for checking if a thread has used floating-point */
+
+#define db_thread_fp_used(thread) ((thread)->pcb->ims.ifps != 0)
+
+/* only a.out symbol tables */
+
+#define DB_NO_COFF 1
+
+#endif /* _I386_DB_MACHDEP_H_ */
diff --git a/i386/i386/db_trace.c b/i386/i386/db_trace.c
new file mode 100644
index 00000000..358d2b10
--- /dev/null
+++ b/i386/i386/db_trace.c
@@ -0,0 +1,674 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include "mach_kdb.h"
+#if MACH_KDB
+
+#include <mach/boolean.h>
+#include <vm/vm_map.h>
+#include <kern/thread.h>
+#include <kern/task.h>
+
+#include <machine/db_machdep.h>
+#include <machine/machspl.h>
+
+#include <ddb/db_access.h>
+#include <ddb/db_command.h>
+#include <ddb/db_output.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_task_thread.h>
+
+#include "trap.h"
+
+db_i386_reg_value(
+ struct db_variable *vp,
+ db_expr_t *valuep,
+ int flag,
+ struct db_var_aux_param *ap); /* forward */
+
+/*
+ * Machine register set.
+ */
+struct db_variable db_regs[] = {
+ { "cs", (int *)&ddb_regs.cs, db_i386_reg_value },
+ { "ds", (int *)&ddb_regs.ds, db_i386_reg_value },
+ { "es", (int *)&ddb_regs.es, db_i386_reg_value },
+ { "fs", (int *)&ddb_regs.fs, db_i386_reg_value },
+ { "gs", (int *)&ddb_regs.gs, db_i386_reg_value },
+ { "ss", (int *)&ddb_regs.ss, db_i386_reg_value },
+ { "eax",(int *)&ddb_regs.eax, db_i386_reg_value },
+ { "ecx",(int *)&ddb_regs.ecx, db_i386_reg_value },
+ { "edx",(int *)&ddb_regs.edx, db_i386_reg_value },
+ { "ebx",(int *)&ddb_regs.ebx, db_i386_reg_value },
+ { "esp",(int *)&ddb_regs.uesp,db_i386_reg_value },
+ { "ebp",(int *)&ddb_regs.ebp, db_i386_reg_value },
+ { "esi",(int *)&ddb_regs.esi, db_i386_reg_value },
+ { "edi",(int *)&ddb_regs.edi, db_i386_reg_value },
+ { "eip",(int *)&ddb_regs.eip, db_i386_reg_value },
+ { "efl",(int *)&ddb_regs.efl, db_i386_reg_value },
+};
+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
+#define SYSCALL 3
+
+db_addr_t db_user_trap_symbol_value = 0;
+db_addr_t db_kernel_trap_symbol_value = 0;
+db_addr_t db_interrupt_symbol_value = 0;
+db_addr_t db_return_to_iret_symbol_value = 0;
+db_addr_t db_syscall_symbol_value = 0;
+boolean_t db_trace_symbols_found = FALSE;
+
+struct i386_kregs {
+ char *name;
+ int offset;
+} i386_kregs[] = {
+ { "ebx", (int)(&((struct i386_kernel_state *)0)->k_ebx) },
+ { "esp", (int)(&((struct i386_kernel_state *)0)->k_esp) },
+ { "ebp", (int)(&((struct i386_kernel_state *)0)->k_ebp) },
+ { "edi", (int)(&((struct i386_kernel_state *)0)->k_edi) },
+ { "esi", (int)(&((struct i386_kernel_state *)0)->k_esi) },
+ { "eip", (int)(&((struct i386_kernel_state *)0)->k_eip) },
+ { 0 },
+};
+
+int *
+db_lookup_i386_kreg(
+ char *name,
+ int *kregp)
+{
+ register struct i386_kregs *kp;
+
+ for (kp = i386_kregs; kp->name; kp++) {
+ if (strcmp(name, kp->name) == 0)
+ return (int *)((int)kregp + kp->offset);
+ }
+ return 0;
+}
+
+db_i386_reg_value(
+ struct db_variable *vp,
+ db_expr_t *valuep,
+ int flag,
+ db_var_aux_param_t ap)
+{
+ int *dp = 0;
+ db_expr_t null_reg = 0;
+ register thread_t thread = ap->thread;
+ extern unsigned int_stack_high;
+
+ if (db_option(ap->modif, 'u')) {
+ if (thread == THREAD_NULL) {
+ if ((thread = current_thread()) == THREAD_NULL)
+ db_error("no user registers\n");
+ }
+ if (thread == current_thread()) {
+ if (ddb_regs.cs & 0x3)
+ dp = vp->valuep;
+ else if (ddb_regs.ebp < int_stack_high)
+ db_error("cannot get/set user registers in nested interrupt\n");
+ }
+ } else {
+ if (thread == THREAD_NULL || thread == current_thread()) {
+ dp = vp->valuep;
+ } else if ((thread->state & TH_SWAPPED) == 0 &&
+ thread->kernel_stack) {
+ dp = db_lookup_i386_kreg(vp->name,
+ (int *)(STACK_IKS(thread->kernel_stack)));
+ if (dp == 0)
+ dp = &null_reg;
+ } else if ((thread->state & TH_SWAPPED) &&
+ thread->swap_func != thread_exception_return) {
+/*.....this breaks t/t $taskN.0...*/
+ /* only EIP is valid */
+ if (vp->valuep == (int *) &ddb_regs.eip) {
+ dp = (int *)(&thread->swap_func);
+ } else {
+ dp = &null_reg;
+ }
+ }
+ }
+ if (dp == 0) {
+ if (thread->pcb == 0)
+ db_error("no pcb\n");
+ dp = (int *)((int)(&thread->pcb->iss) +
+ ((int)vp->valuep - (int)&ddb_regs));
+ }
+ if (flag == DB_VAR_SET)
+ *dp = *valuep;
+ else
+ *valuep = *dp;
+}
+
+void
+db_find_trace_symbols(void)
+{
+ db_expr_t value;
+ if (db_value_of_name("_user_trap", &value))
+ db_user_trap_symbol_value = (db_addr_t) value;
+ if (db_value_of_name("_kernel_trap", &value))
+ db_kernel_trap_symbol_value = (db_addr_t) value;
+ if (db_value_of_name("_interrupt", &value))
+ db_interrupt_symbol_value = (db_addr_t) value;
+ if (db_value_of_name("_return_to_iret", &value))
+ db_return_to_iret_symbol_value = (db_addr_t) value;
+ if (db_value_of_name("_syscall", &value))
+ db_syscall_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_default = 5;
+
+int
+db_numargs(
+ struct i386_frame *fp,
+ task_t task)
+{
+ int *argp;
+ int inst;
+ int args;
+ extern char etext[];
+
+ argp = (int *)db_get_task_value((int)&fp->f_retaddr, 4, FALSE, task);
+ if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext)
+ args = db_numargs_default;
+ else if (!DB_CHECK_ACCESS((int)argp, 4, task))
+ args = db_numargs_default;
+ else {
+ inst = db_get_task_value((int)argp, 4, FALSE, task);
+ if ((inst & 0xff) == 0x59) /* popl %ecx */
+ args = 1;
+ else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
+ args = ((inst >> 16) & 0xff) / 4;
+ else
+ args = db_numargs_default;
+ }
+ return args;
+}
+
+struct interrupt_frame {
+ struct i386_frame *if_frame; /* point to next frame */
+ int if_retaddr; /* return address to _interrupt */
+ int if_unit; /* unit number */
+ spl_t if_spl; /* saved spl */
+ int if_iretaddr; /* _return_to_{iret,iret_i} */
+ int if_edx; /* old sp(iret) or saved edx(iret_i) */
+ int if_ecx; /* saved ecx(iret_i) */
+ int if_eax; /* saved eax(iret_i) */
+ int if_eip; /* saved eip(iret_i) */
+ int if_cs; /* saved cs(iret_i) */
+ int if_efl; /* saved efl(iret_i) */
+};
+
+/*
+ * 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(
+ struct i386_frame **lfp, /* in/out */
+ struct i386_frame **fp, /* in/out */
+ db_addr_t *ip, /* out */
+ int frame_type, /* in */
+ thread_t thread) /* in */
+{
+ struct i386_saved_state *saved_regs;
+ struct interrupt_frame *ifp;
+ task_t task = (thread != THREAD_NULL)? thread->task: TASK_NULL;
+
+ switch(frame_type) {
+ case TRAP:
+ /*
+ * We know that trap() has 1 argument and we know that
+ * it is an (struct i386_saved_state *).
+ */
+ saved_regs = (struct i386_saved_state *)
+ db_get_task_value((int)&((*fp)->f_arg0),4,FALSE,task);
+ db_printf(">>>>> %s (%d) at ",
+ trap_name(saved_regs->trapno), saved_regs->trapno);
+ db_task_printsym(saved_regs->eip, DB_STGY_PROC, task);
+ db_printf(" <<<<<\n");
+ *fp = (struct i386_frame *)saved_regs->ebp;
+ *ip = (db_addr_t)saved_regs->eip;
+ break;
+ case INTERRUPT:
+ if (*lfp == 0) {
+ db_printf(">>>>> interrupt <<<<<\n");
+ goto miss_frame;
+ }
+ db_printf(">>>>> interrupt at ");
+ ifp = (struct interrupt_frame *)(*lfp);
+ *fp = ifp->if_frame;
+ if (ifp->if_iretaddr == db_return_to_iret_symbol_value)
+ *ip = ((struct i386_interrupt_state *) ifp->if_edx)->eip;
+ else
+ *ip = (db_addr_t) ifp->if_eip;
+ db_task_printsym(*ip, DB_STGY_PROC, task);
+ db_printf(" <<<<<\n");
+ break;
+ case SYSCALL:
+ if (thread != THREAD_NULL && thread->pcb) {
+ *ip = (db_addr_t) thread->pcb->iss.eip;
+ *fp = (struct i386_frame *) thread->pcb->iss.ebp;
+ break;
+ }
+ /* falling down for unknown case */
+ default:
+ miss_frame:
+ *ip = (db_addr_t)
+ db_get_task_value((int)&(*fp)->f_retaddr, 4, FALSE, task);
+ *lfp = *fp;
+ *fp = (struct i386_frame *)
+ db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
+ break;
+ }
+}
+
+void
+db_i386_stack_trace(
+ thread_t th,
+ struct i386_frame *frame,
+ db_addr_t callpc,
+ db_expr_t count,
+ int flags); /* forward */
+
+#define F_USER_TRACE 1
+#define F_TRACE_THREAD 2
+
+void
+db_stack_trace_cmd(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ char *modif)
+{
+ boolean_t trace_thread = FALSE;
+ struct i386_frame *frame;
+ db_addr_t callpc;
+ int flags = 0;
+ thread_t th;
+
+ {
+ register char *cp = modif;
+ register char c;
+
+ while ((c = *cp++) != 0) {
+ if (c == 't')
+ trace_thread = TRUE;
+ if (c == 'u')
+ flags |= F_USER_TRACE;
+ }
+ }
+
+ if (!have_addr && !trace_thread) {
+ frame = (struct i386_frame *)ddb_regs.ebp;
+ callpc = (db_addr_t)ddb_regs.eip;
+ th = current_thread();
+ } else if (trace_thread) {
+ if (have_addr) {
+ th = (thread_t) addr;
+ if (!db_check_thread_address_valid((db_addr_t)th))
+ return;
+ } else {
+ th = db_default_thread;
+ if (th == THREAD_NULL)
+ th = current_thread();
+ if (th == THREAD_NULL) {
+ db_printf("no active thread\n");
+ return;
+ }
+ }
+ if (th == current_thread()) {
+ frame = (struct i386_frame *)ddb_regs.ebp;
+ callpc = (db_addr_t)ddb_regs.eip;
+ } else {
+ if (th->pcb == 0) {
+ db_printf("thread has no pcb\n");
+ return;
+ }
+ if ((th->state & TH_SWAPPED) || th->kernel_stack == 0) {
+ register struct i386_saved_state *iss = &th->pcb->iss;
+
+ db_printf("Continuation ");
+ db_task_printsym((db_expr_t)th->swap_func,
+ DB_STGY_PROC,
+ th->task);
+ db_printf("\n");
+
+ frame = (struct i386_frame *) (iss->ebp);
+ callpc = (db_addr_t) (iss->eip);
+ } else {
+ register struct i386_kernel_state *iks;
+ iks = STACK_IKS(th->kernel_stack);
+ frame = (struct i386_frame *) (iks->k_ebp);
+ callpc = (db_addr_t) (iks->k_eip);
+ }
+ }
+ } else {
+ frame = (struct i386_frame *)addr;
+ th = (db_default_thread)? db_default_thread: current_thread();
+ callpc = (db_addr_t)db_get_task_value((int)&frame->f_retaddr, 4,
+ FALSE,
+ (th == THREAD_NULL) ? TASK_NULL : th->task);
+ }
+
+ db_i386_stack_trace( th, frame, callpc, count, flags );
+}
+
+
+void
+db_i386_stack_trace(
+ thread_t th,
+ struct i386_frame *frame,
+ db_addr_t callpc,
+ db_expr_t count,
+ int flags)
+{
+ task_t task;
+ boolean_t kernel_only;
+ int *argp;
+ int user_frame = 0;
+ struct i386_frame *lastframe;
+ int frame_type;
+ char *filename;
+ int linenum;
+ extern unsigned int db_maxoff;
+
+ if (count == -1)
+ count = 65535;
+
+ kernel_only = (flags & F_USER_TRACE) == 0;
+
+ task = (th == THREAD_NULL) ? TASK_NULL : th->task;
+
+ if (!db_trace_symbols_found)
+ db_find_trace_symbols();
+
+ if (!INKERNEL((unsigned)callpc) && !INKERNEL((unsigned)frame)) {
+ db_printf(">>>>> user space <<<<<\n");
+ user_frame++;
+ }
+
+ lastframe = 0;
+ while (count-- && frame != 0) {
+ register int narg;
+ char * name;
+ db_expr_t offset;
+
+ if (INKERNEL((unsigned)callpc) && user_frame == 0) {
+ db_addr_t call_func = 0;
+
+ db_symbol_values(0, db_search_task_symbol(callpc,
+ DB_STGY_XTRN, (db_addr_t *)&offset,
+ TASK_NULL),
+ &name, (db_expr_t *)&call_func);
+ if (call_func == db_user_trap_symbol_value ||
+ call_func == db_kernel_trap_symbol_value) {
+ frame_type = TRAP;
+ narg = 1;
+ } else if (call_func == db_interrupt_symbol_value) {
+ frame_type = INTERRUPT;
+ goto next_frame;
+ } else if (call_func == db_syscall_symbol_value) {
+ frame_type = SYSCALL;
+ goto next_frame;
+ } else {
+ frame_type = 0;
+ narg = db_numargs(frame, task);
+ }
+ } else if (INKERNEL((unsigned)callpc) ^ INKERNEL((unsigned)frame)) {
+ frame_type = 0;
+ narg = -1;
+ } else {
+ frame_type = 0;
+ narg = db_numargs(frame, task);
+ }
+
+ db_find_task_sym_and_offset(callpc, &name,
+ (db_addr_t *)&offset, task);
+ if (name == 0 || offset > db_maxoff) {
+ db_printf("0x%x(", callpc);
+ offset = 0;
+ } else
+ db_printf("%s(", name);
+
+ argp = &frame->f_arg0;
+ while (narg > 0) {
+ db_printf("%x", db_get_task_value((int)argp,4,FALSE,task));
+ argp++;
+ if (--narg != 0)
+ db_printf(",");
+ }
+ if (narg < 0)
+ db_printf("...");
+ db_printf(")");
+ if (offset) {
+ db_printf("+%x", offset);
+ }
+ if (db_line_at_pc(0, &filename, &linenum, callpc)) {
+ db_printf(" [%s", filename);
+ if (linenum > 0)
+ db_printf(":%d", linenum);
+ db_printf("]");
+ }
+ db_printf("\n");
+
+ next_frame:
+ db_nextframe(&lastframe, &frame, &callpc, frame_type, th);
+
+ if (frame == 0) {
+ /* end of chain */
+ break;
+ }
+ if (!INKERNEL(lastframe) ||
+ (!INKERNEL((unsigned)callpc) && !INKERNEL((unsigned)frame)))
+ user_frame++;
+ if (user_frame == 1) {
+ db_printf(">>>>> user space <<<<<\n");
+ if (kernel_only)
+ break;
+ }
+ if (frame <= lastframe) {
+ if (INKERNEL(lastframe) && !INKERNEL(frame))
+ continue;
+ db_printf("Bad frame pointer: 0x%x\n", frame);
+ break;
+ }
+ }
+}
+
+#define CTHREADS_SUPPORT 1
+
+#if CTHREADS_SUPPORT
+
+thread_t
+db_find_kthread(
+ vm_offset_t ustack_base,
+ vm_size_t ustack_top,
+ task_t task)
+{
+ thread_t thread;
+
+ queue_iterate(&task->thread_list, thread, thread_t, thread_list) {
+ vm_offset_t usp = thread->pcb->iss.uesp/*ebp works*/;
+ if (usp >= ustack_base && usp < ustack_top)
+ return thread;
+ }
+ return THREAD_NULL;
+}
+
+static void db_cproc_state(
+ int state,
+ char s[4])
+{
+ if (state == 0) {
+ *s++ = 'R';
+ } else {
+ if (state & 1) *s++ = 'S';
+ if (state & 2) *s++ = 'B';
+ if (state & 4) *s++ = 'C';
+ }
+ *s = 0;
+}
+
+/* offsets in a cproc structure */
+int db_cproc_next_offset = 0 * 4;
+int db_cproc_incarnation_offset = 1 * 4;
+int db_cproc_list_offset = 2 * 4;
+int db_cproc_wait_offset = 3 * 4;
+int db_cproc_context_offset = 5 * 4;
+int db_cproc_state_offset = 7 * 4;
+int db_cproc_stack_base_offset = 10 * 4 + sizeof(mach_msg_header_t);
+int db_cproc_stack_size_offset = 11 * 4 + sizeof(mach_msg_header_t);
+
+/* offsets in a cproc_switch context structure */
+int db_cprocsw_framep_offset = 3 * 4;
+int db_cprocsw_pc_offset = 4 * 4;
+
+#include <machine/setjmp.h>
+
+extern jmp_buf_t *db_recover;
+
+void db_trace_cproc(
+ vm_offset_t cproc,
+ thread_t thread)
+{
+ jmp_buf_t db_jmpbuf;
+ jmp_buf_t *prev = db_recover;
+ task_t task;
+ db_addr_t pc, fp;
+
+ task = (thread == THREAD_NULL)? TASK_NULL: thread->task;
+
+ if (!_setjmp(db_recover = &db_jmpbuf)) {
+ char pstate[4];
+ unsigned int s, w, n, c, cth;
+
+ s = db_get_task_value(cproc + db_cproc_state_offset, 4, FALSE, task);
+ w = db_get_task_value(cproc + db_cproc_wait_offset, 4, FALSE, task);
+ n = db_get_task_value(cproc + db_cproc_next_offset, 4, FALSE, task);
+ c = db_get_task_value(cproc + db_cproc_context_offset, 4, FALSE, task);
+ cth = db_get_task_value(cproc + db_cproc_incarnation_offset, 4, FALSE, task);
+
+ db_cproc_state(s, pstate);
+
+ db_printf("CThread %x (cproc %x) %s", cth, cproc, pstate);
+ if (w) db_printf(" awaits %x", w);
+ if (n) db_printf(" next %x", n);
+ db_printf("\n");
+
+ if ((s != 0) && (c != 0)) {
+ pc = db_get_task_value(c + db_cprocsw_pc_offset, 4, FALSE, task);
+ fp = c + db_cprocsw_framep_offset;
+ } else {
+ db_addr_t sb;
+ vm_size_t ss;
+
+ sb = db_get_task_value(cproc + db_cproc_stack_base_offset, sizeof(db_expr_t), FALSE, task);
+ ss = db_get_task_value(cproc + db_cproc_stack_size_offset, sizeof(db_expr_t), FALSE, task);
+ db_printf(" Stack base: %x\n", sb);
+ /*
+ * Lessee now..
+ */
+ thread = db_find_kthread(sb, sb+ss, task);
+ if (thread != THREAD_NULL) {
+ pc = thread->pcb->iss.eip;
+ fp = thread->pcb->iss.ebp;
+ } else
+ fp = -1;
+ }
+
+ if (fp != -1)
+ db_i386_stack_trace(thread, (struct i386_frame*)fp, pc,
+ -1, F_USER_TRACE);
+ }
+
+ db_recover = prev;
+}
+
+void db_all_cprocs(
+ task_t task,
+ db_expr_t cproc_list)
+{
+ jmp_buf_t db_jmpbuf;
+ jmp_buf_t *prev = db_recover;
+ thread_t thread;
+ db_expr_t cproc, next;
+
+
+ if (task != TASK_NULL) {
+ thread = (thread_t) queue_first(&task->thread_list);
+ } else
+ thread = current_thread();
+
+ if (cproc_list != 0)
+ next = cproc_list;
+ else
+ if (!db_value_of_name("unix::cproc_list", &next)) {
+ db_printf("No cprocs.\n");
+ return;
+ }
+
+
+ while (next) {
+ if (_setjmp(db_recover = &db_jmpbuf))
+ break;
+
+ cproc = db_get_task_value(next, 4, FALSE, TASK_NULL);
+ if (cproc == 0) break;
+ next = cproc + db_cproc_list_offset;
+
+ db_trace_cproc(cproc, thread);
+ }
+
+ db_recover = prev;
+}
+
+#endif /* CTHREADS_SUPPORT */
+
+#endif MACH_KDB
diff --git a/i386/i386/debug.h b/i386/i386/debug.h
new file mode 100644
index 00000000..99108b69
--- /dev/null
+++ b/i386/i386/debug.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+#ifndef _I386_DEBUG_
+#define _I386_DEBUG_
+
+
+#ifdef DEBUG
+
+
+/* Maximum number of entries in a debug trace.
+ If the buffer overflows, the oldest entries are forgotten. */
+#define DEBUG_TRACE_LEN 512
+
+/* Add the caller's current position to the debug trace buffer.
+ Only the kernel stack needs to be valid;
+ the other data segment registers are not needed
+ and all registers are saved. */
+#ifndef ASSEMBLER
+
+/* Dump a saved state.
+ Probably a good idea to have this around
+ even when DEBUG isn't turned on. */
+void dump_ss(struct i386_saved_state *st);
+
+#define DEBUG_TRACE _debug_trace(__FILE__,__LINE__)
+
+/* Reset the debug trace buffer so it contains no valid entries. */
+void debug_trace_reset(void);
+
+/* Dump the contents of the trace buffer to the console.
+ Also clears the trace buffer. */
+void debug_trace_dump(void);
+
+#else ASSEMBLER
+
+#define DEBUG_TRACE \
+ pushl $__LINE__ ;\
+ pushl $9f ;\
+ call __debug_trace ;\
+ addl $8,%esp ;\
+ .data ;\
+9: .ascii __FILE__"\0" ;\
+ .text
+
+#endif ASSEMBLER
+
+
+#endif DEBUG
+
+/* XXX #include_next "debug.h" */
+
+#endif _I386_DEBUG_
diff --git a/i386/i386/debug_i386.c b/i386/i386/debug_i386.c
new file mode 100644
index 00000000..c8cd5635
--- /dev/null
+++ b/i386/i386/debug_i386.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+
+#include "thread.h"
+#include "trap.h"
+#include "debug.h"
+
+void dump_ss(struct i386_saved_state *st)
+{
+ printf("Dump of i386_saved_state %08x:\n", st);
+ printf("EAX %08x EBX %08x ECX %08x EDX %08x\n",
+ st->eax, st->ebx, st->ecx, st->edx);
+ printf("ESI %08x EDI %08x EBP %08x ESP %08x\n",
+ st->esi, st->edi, st->ebp, st->uesp);
+ printf("CS %04x SS %04x DS %04x ES %04x FS %04x GS %04x\n",
+ st->cs & 0xffff, st->ss & 0xffff,
+ st->ds & 0xffff, st->es & 0xffff,
+ st->fs & 0xffff, st->gs & 0xffff);
+ printf("v86: DS %04x ES %04x FS %04x GS %04x\n",
+ st->v86_segs.v86_ds & 0xffff, st->v86_segs.v86_es & 0xffff,
+ st->v86_segs.v86_gs & 0xffff, st->v86_segs.v86_gs & 0xffff);
+ printf("EIP %08x EFLAGS %08x\n", st->eip, st->efl);
+ printf("trapno %d: %s, error %08x\n",
+ st->trapno, trap_name(st->trapno),
+ st->err);
+}
+
+#ifdef DEBUG
+
+struct debug_trace_entry
+{
+ char *filename;
+ int linenum;
+};
+struct debug_trace_entry debug_trace_buf[DEBUG_TRACE_LEN];
+int debug_trace_pos;
+
+
+void
+debug_trace_reset()
+{
+ int s = splhigh();
+ debug_trace_pos = 0;
+ debug_trace_buf[DEBUG_TRACE_LEN-1].filename = 0;
+ splx(s);
+}
+
+static void
+print_entry(int i, int *col)
+{
+ char *fn, *p;
+
+ /* Strip off the path from the filename. */
+ fn = debug_trace_buf[i].filename;
+ for (p = fn; *p; p++)
+ if (*p == '/')
+ fn = p+1;
+
+ printf(" %9s:%-4d", fn, debug_trace_buf[i].linenum);
+ if (++*col == 5)
+ {
+ printf("\n");
+ *col = 0;
+ }
+}
+
+void
+debug_trace_dump()
+{
+ int s = splhigh();
+ int i;
+ int col = 0;
+
+ printf("Debug trace dump ");
+
+ /* If the last entry is nonzero,
+ the trace probably wrapped around.
+ Print out all the entries after the current position
+ before all the entries before it,
+ so we get a total of DEBUG_TRACE_LEN entries
+ in correct time order. */
+ if (debug_trace_buf[DEBUG_TRACE_LEN-1].filename != 0)
+ {
+ printf("(full):\n");
+
+ for (i = debug_trace_pos; i < DEBUG_TRACE_LEN; i++)
+ {
+ print_entry(i, &col);
+ }
+ }
+ else
+ printf("(%d entries):\n", debug_trace_pos);
+
+ /* Print the entries before the current position. */
+ for (i = 0; i < debug_trace_pos; i++)
+ {
+ print_entry(i, &col);
+ }
+
+ if (col != 0)
+ printf("\n");
+
+ debug_trace_reset();
+
+ splx(s);
+}
+
+#include "syscall_sw.h"
+
+int syscall_trace = 0;
+
+int
+syscall_trace_print(int syscallvec, ...)
+{
+ int syscallnum = syscallvec >> 4;
+ int i;
+
+ printf("syscall -%d:", syscallnum);
+ for (i = 0; i < mach_trap_table[syscallnum].mach_trap_arg_count; i++)
+ printf(" %08x", (&syscallvec)[1+i]);
+ printf("\n");
+
+ return syscallvec;
+}
+
+#endif DEBUG
+
diff --git a/i386/i386/debug_trace.S b/i386/i386/debug_trace.S
new file mode 100644
index 00000000..a263bcfd
--- /dev/null
+++ b/i386/i386/debug_trace.S
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+
+#ifdef DEBUG
+
+#include <mach/machine/asm.h>
+
+#include "debug.h"
+
+ .text
+ENTRY(_debug_trace)
+ pushf
+ cli
+ pushl %eax
+ pushl %ebx
+ .byte 0x36 /* SS: bug in gas? */
+ movl %ss:EXT(debug_trace_pos),%eax
+ movl 16(%esp),%ebx
+ movl %ebx,%ss:EXT(debug_trace_buf)(,%eax,8)
+ movl 20(%esp),%ebx
+ movl %ebx,%ss:EXT(debug_trace_buf)+4(,%eax,8)
+ incl %eax
+ andl $DEBUG_TRACE_LEN-1,%eax
+ .byte 0x36 /* SS: bug in gas? */
+ movl %eax,%ss:EXT(debug_trace_pos)
+ popl %ebx
+ popl %eax
+ popf
+ ret
+
+#endif DEBUG
+
+/* XXX gas bug? need at least one symbol... */
+foo:
+
diff --git a/i386/i386/eflags.h b/i386/i386/eflags.h
new file mode 100644
index 00000000..26ce3d91
--- /dev/null
+++ b/i386/i386/eflags.h
@@ -0,0 +1,35 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+#ifndef _KERNEL_I386_EFLAGS_H_
+#define _KERNEL_I386_EFLAGS_H_
+
+#include <mach/machine/eflags.h>
+
+/* Eflags bit combinations used by the Mach kernel. */
+#define EFL_USER_SET (EFL_IF)
+#define EFL_USER_CLEAR (EFL_IOPL|EFL_NT|EFL_RF)
+
+#endif _KERNEL_I386_EFLAGS_H_
diff --git a/i386/i386/fpe.b b/i386/i386/fpe.b
new file mode 100755
index 00000000..10a8e65d
--- /dev/null
+++ b/i386/i386/fpe.b
@@ -0,0 +1,478 @@
+
+begin 644 fpe.o
+M!P$``+12`````````````#````````````````````!@'@8/H`^HB>7I:@D`
+M`(GL#ZD/H0<?8<\`````5E>+?"00#[1W/(M',#T`````#X27````/0$```!U
+M"(/&(.F(````/0(```!U!8/&).M\/0,```!U!8/&*.MP/04```!U!8/&+.MD
+M/1(```!T)3T4````="0]%0```'0C/18```!T(CT7````=$&+=QADK6:)1P!D
+MK6:)1P1DK6:)1PADK6:)1PQDK8E'$&2MB4<49*V)1QB#Q@1DK8E'(&2MB4<D
+M9*V)1RADK8E'+&2MB4<P9*UFB4<T9*V)1SB)=SQFC&=`7U[+````````````
+M`,#__P````````"`_W\`````````````___________^?T(Q``!",0``V!(`
+M`+(2``!*!```2@0``)4&```K!0``2@0``$H$``"5!@``*P4``&4&``!E!@``
+M"@<``%,&```*!0``"@4``(,&``#?!```2@0``$H$``!^!@``*P4``$H$``!*
+M!```?@8``"L%``!E!@``908```H'``!3!@``"@4```H%``!L!@``WP0``$H$
+M``"S!@``\08``"L%``"S!@``LP8``"$'``"A!@``\08``"$'``#Q!@``PP8`
+M``H%``"A!@``PP8``-\$``!*!```VP8``+,&```K!0``LP8``"$'``"S!@``
+MH08``/$&``#Q!@``(0<``,,&```*!0``VP8``*$&``#?!```ON@```#&1<3_
+MQD7&`HU]O!X.'Q8'N0(```#SI8E-N(L&9HE%R!_#'@'N%A\6!XU]N+D%````
+M\Z4?PV6`#00````(9?8%``````AU/X%MR`!@``"!?<C_?P``?2^`O7#_____
+M#X6D````98`-!````""`O6______#X6/````98`-!0````+I@@```&6`#00`
+M```@Z/(C```\#'0<BD7$Z*`C``!U$F6`#04````"OO(```#I4?___\=%R/Y_
+M``#'1;@`````QT6\_____\=%P/____^`O73___\%?#"`O73___\(?R>R`V4B
+M%0$```"`^@)_&700QT6\`````,=%P`#____K!X%EO`#X___&1<8`PV7V!0``
+M```0=2!E@`T$````$(%%R`!@``"#?<@`#X\G____@6W(`&```+^X____N`$`
+M``#HDT(``.@@(P``L/^_N/___^@J(@``9H.]</___P!T)&6`#00````P@+UO
+M_____W4398`-!0````+V1<.`=`7&1<8`PS'`B47(O[S____H?DP``,9%Q@9U
+M!,9%Q@'#@WP]$`!U+,=$/1`!````]D0]"X!U'0^]3#T(=!>+1#T$@^D?]]D/
+MI40]"--D/00I3#T0PXM$/00/O<B#Z1_WV=/@B40]",=$/00`````@\$@Z]QT
+M'>A5(P``9?8%``````$/A!H!``#H[_W__^F:````98`E!0```/V*18X*1:(/
+MA00!```/MIUT____@.L%9L'C`B[_DQ`!``"_N/___^@G(@``L`#H-B$``+^X
+M____Z&I!``"+1<@]_G\```^/MP```(/X``^,M@```.B7_O__(<!U%+^\____
+MZ)-+```/A9T```#&1<8!@+UP_____W4998`-!````""`O6______=0AE@`T%
+M`````K^X____OGS____I+P$``&6`#00````"9?8%``````)T5;^`____Z,G^
+M__^_E/___^B__O__Z4#___]E@`T$`````F7V!0`````"="J_@/___^B>_O__
+MZ1____]E@`T$`````F7V!0`````"=`GKO.@6_?__ZXK#Z.;]___K@J@0="9E
+M@`T$`````67V!0`````!=.*_@/___^@J&```OGS____IE@```(!]C@)T#(!]
+MH@(/A9````#K#/9%BT!T#(!]H@)U&/9%GT!U$F6`#00````!9?8%``````%T
+MF+Y\____@'V.`G0'OY3____K28!]H@)T![^`____ZSR*18R*9:!0@&6+?X!E
+MGW_&18P`QD6@`,:%=/___P96Z%$K``!>6(A%C+^`____@'W$`'0(B&6@OY3_
+M__^`3#T+P.B1%```Z14B``"*7:**?8[VQP1T`K<#]L,$=`*S`X'C`P,``,#G
+M`@#[,/_!XP*X^T````*%=/____;D`<,N_Z,@`0``PV6`#00````"9?8%````
+M``)T[;Z`____ZRYE@`T$`````F7V!0`````"=-3V5:#K$F6`#00````"9?8%
+M``````)TO;Z4____Z*C[___K9&6`#00````"9?8%``````)TG[[\````Z'#[
+M___&1<8!ZS-E@`T$`````F7V!0`````"#X1Y____ZQ9E@`T$````!&7V!0``
+M```$#X1A____Z-C[___&1<0`BF6,.F6@=`/V5<3IQOW__XIEH("]=/___P9U
+M`O;4.F6,#X1$____98`-!`````%E]@4``````0^$&____^CD^O__Z8_]__\`
+M``!B#@``GPX``+T.``!2#P``DPX``"00``#Q#@``1Q```)<.``"G#@``%0\`
+M`.</``";#@``I0X``"X/```0$```'PT``"T-```V#0``0@T``",-```H#0``
+M.@T``#$-``#^#0```@X```8.```*#@``#@X``!4.```A#@``)0X``"D.```Q
+M#@``.0X``$$.``!)#@``2@X``%(.``!:#@``?1H``$`J```1'P``<C(``#LH
+M```7!```%P0``!<$```7!```@2D``!8=``!3'0``.R@``/8>``!A*0``5QX`
+M`!,Z```3.@``VS\``"A*```3.@``_!4``.$?``!<%```M2,``+D=```[*```
+MMB@``)<I``#0*0``KRD``/03``#T$P``]!,``/03``#T$P``]!,``/03``"7
+M*```DR@``*4I``!R,@``Z1T``"),``#'30``Q$X``.$?``!R,@``!0<#,`8Q
+M"#(`A`$SFXF<G0`9C#,"#82$*2J$A!\@(2(C)"6$$A`3%`\N)B<6$14M%Q@K
+M+`"$`3,``#,SC(RHCHR$A(0`A`$SBX2*GAH9`3,O-(2$&ADS,YZ$A(0```<'
+M!0$%`0<'!P<'!P<'!P`%`04"!0-$1```0$````P,#`P,#`P`1&A'F$=D``!D
+M:$1'1)1$1`,'!04'!0<%``<!`0```0$%!P,#!P4'!0$'```#`P```0`'!P4!
+M!0$'!P<'!P<'!P('!04(!`4%!0<"`@4%"`2![)@```!FC-!FCMAFCL!F+HL5
+M&````&:.Z@\"T/?"``!``'40@>3__P``@>7__P``LP'K`K,`B%T"]T4X```"
+M`'40QD4#`6:)1?J-13R)11SK,L9%`P"+13R)11QFBT5`9HE%^F:+141FB44(
+M9HM%2&:)10QFBT5,9HE%!&:+15!FB44`_+DD````C;UH____,<#SJ_RR!XC1
+M9KL"`H!]`P%U(,5U,,9%^`'&1?D!#P)%-*D``$``=1S&1?@`QD7Y`.L2#[=U
+M-,'F!`-U,,9%^`#&1?D`9HL&1B2'>?B`Q$#0T-#`9KX`.&8AQF;![@MFOQX`
+M9B''9M'G#A\/O_8/O_\N_Y=$!P``@.0'9HF%=/___V:)E7;___]FB8UY____
+M9HFU?/___V:)O7[___^(O7C___^(G7O___^`?0,!=1+%=3")M6[___]FC)UR
+M____ZQN+=3")M6[___\/MTTT9HF-<O___\'A!`'.%A]F,<DQVV:+50QFBP9&
+M(,!X0#QG=0:`=?D!Z^X\9G4&@'7X`>OD9DEFBU4$/&1TVF:+50`\97329HM5
+M"#PF=,IFBU4T/"YTPF:+5?H\-G2ZZ[1&B./V1?D!#X4)`@``#[<&4&:+10QF
+MCMA8@/O`#X.(````T.-R$7@,@.,.@/L,=!-F,<!.3F:8@^,.T>,N_Y.$!P``
+M1D:`?0,!=2=FB95L____B85H____]H5T____@'5)969EB148````9:,4````
+MZS@/M]+!X@0!T&:,TF:)E6S___^)A6C____VA73___^`=1=E9J,4````B<+!
+MZA#!X@QE98D5&````(!]`P%U!8EU_.L,#[=5-,'B!"G6B77\OG;___^_@/__
+M_\=%J`````#'1:P`````QT6P`````,=%M`````#H-`T``&90OGG___^_E/__
+M_^@C#0``9EMF"=B*G73____0TW,5BHUT____@/F;=W&`^8YT;(#YBG1G966*
+M#0````#VT8#A/V4B#00```!T!,T0Z^;VA73___^`=42`?0,!=1E0Q(5N____
+M9:,,````969EC`40````6.LE4`^WA7+____!X`0#A6[___]E9J,,````P>@0
+MP>`,9:,0````6`^_V]'#9@G`+O^3Y`<``&5EB@4`````]M`D?V4B!00```!T
+M(+``BHUT____]L&`=`6`^9MW&&9E@0T$````@("P`NL*9F6!)00```!_?XM-
+M_(E-,")%.70"S1#I[_+__V8#12!F`T44PV8#11##9@-%$&8#12##9@-%%&8#
+M11AGXP?#9@-%$.OR9HM5^L,Q_X#\P',+@.0'@/P$=0.*/D:+!AX/H5!FBT4,
+M9H[86(#[P`^#:_[__X/&!-#C<AAX$(#C#D>`^PH/A/#]__\QP$Z#[@,/OL"`
+MXP^`^PAT$8/C#M'C+O^3I`<``.G._?__B/LA_W00@.<'@/\%=0ADBP:#Q@3K
+M$V:)WX/C!\'C`B[_DZ0'``!FB?N(WX#G.(#_(`^$E_W__XC9P,$"@.$#T.N#
+MXQPN_Y/$!P``Z7[]__\#12S#`T4HPP-%),,#12##`T4<9^,(PP-%&&?C`<-F
+MBU7ZPP-%%,,#11##BWTLT^<!^,.+?2C3YP'XPXM])-/G`?C#BWT@T^<!^,/#
+MBWT8T^<!^,.+?133YP'XPXM]$-/G`?C#L0"U`(J&I`@``&:)UV:Z!0%FB=8\
+M,70-/#)T#3PP=02P`[<!P[`&ZP*P"(;?9H?*P[$#Z\VQ`>O)L0+KQ6:Y!03K
+MP;,!BH:D"```9HG79KH%`6:Y!01FB<[KN8J&K`@``&;1Y@^_]F:+E@`)``!F
+MO@``9HG//`!T##PS=`T\`70-9HG^PV:^!0/#MP&P`<.*AM@(``"*ED@)``"*
+MME`)``!F4HJ6.`D``(JV0`D``&9>Z[^*AN@(``!FT>8/O_9FBY98"0``9KX!
+M`.NFBH;8"```BI9P"0``BK90"0``9E**EF@)``"*MD`)``!F7NN"]L0@=$YF
+MO@`?9B'&9L'N"`^_]HJ&&`D``-#`N00```#`P`)FOP8`9B''#[__9O^W$`D`
+M`.+JBH:X"```/!!T"#P1=`0\%'4"MP%F7V9>9EEF6L-FB<^*AK0(```\`'00
+M/!ET%3PS="`\`70@9HG^PV:Z!01FO@4#PV:Z!0%FN04$9HG.9HG7P[`!MP%F
+MN@4!9KX%!,.*AO`(```\-'4$MP&P+SPO=0]FN04$9HG79HG69KH%`<,\&G6B
+MMP#KGHJ&^`@``#P:=0*S`3R>=>BU!.OD@/PI=16S`;<!L"]FN04$9HG79HG6
+M9KH%`<.PA&:)SF:)S\-FO@`'9B'&9L'N"`^_]HJ&X`@``.OC9K@!`,,``!PD
+M.40<)#Q$OKRZN0$"`@(!`@(#O[C____HYC\``+^`____L0'H834``.C]%0``
+M@/H#=`:*38.(3;H/MMJ_=!```"X/M@P[B(UH____C76$-O]V!/9%`@%T!0^W
+MU.L"B>))=0%!-O\V@^X$XOB)R+]P$```+HH,.XB-;O___U#B_8G3B<>*C6C_
+M__]1-HL3.U6<=0NX_____S:+4_SK%C:+0_SW=9R)1;")5:SK$HM%L$B+5:R)
+M1;`#59QR%HE5K(M%L/=EF#M5K'((=^$V.T/X=]LQP(E%M(J%;O___XG!P>`"
+M]]B)QHM$-:#W9;`V*00S<P%"BT6T-BD$,W,!0HE5M(/&!.+@-BD4,W,D_TVP
+MBHUN____B<C!X`+WV(G&^(M$-:`V$00S@\8$XO,V$0PSBT6PB40]P%E)=`N#
+MZP2#[P3I1/___XG(B<:*C6[____0X68V"T0S_H/N`N+U",0(9;J)SHJ-;O__
+M_S:+1#/\B40UB(/N!.+RBHUH____`HUN____@/D"=0%!P>$"`<S#:&00``#K
+M!6AH$```O[C____H73X``+^4____L0'HV#,``.AT%```#[;:7RZ*!#N(A6[_
+M__\N#[:#;!```(G'BT6`BUV$BU6(#ZS8`@^LTP+!Z@+K#='@T=/1TG(0@$P]
+M`B`K190;79@;59SK!>@W````Z#P```#^C6[___]UUB'2>`>`3#T"(.L%Z!H`
+M``")18")782)58@)V`G0#Z3"$&8)T`C$B&6ZPP-%E!-=F!-5G,/19;C15;S1
+M5<##BT60*T6D!?\_``")1<B*18PR1:"(1<3HJOW__[^X____Z>H^``"+19`#
+M1:0M_C\``(E%R(I%C#)%H(A%Q.@*````O[C____IQ#X``!Z_K/___Q8?C5P]
+M`.A9/0``O[C____H43T``+D(````OY3____H#ST``'4$`<\!R[Z`____BT0U
+M!`M$-0!U!`'.`<M7BWP]`#')BT0U`/?G`0,1T8/^@'0%B4L$ZR:+1#4$]^<!
+MR(/2`#')`4,$$=&+1#4(]^<!R(/2``%#"(/2`(E3#%^#PP2#QP2#_Z!UL[^L
+M____Z+L\``!T!(!-N@$?PP```````````(#_/P!`_HH;S4MXFM0`0`#`N_`7
+M7"D[JKC_/P#`-,)H(:+:#\D`0`"@F/?/^X2:()K]/P#@JWG/T?<7<K'^/P``
+M`````````````-#KN`8```#VXP4L$@``B<;'1;@`````9BZ+!F:)1;HNBT8"
+MB46\+HM&!HE%P"X/MT8*B47(,<")1<2R`[^X____Z&P1``"_N/___^B@,0``
+M98`E!0```/TQP(M%J)^_N/___^E#!@``=!3H$!,``&7V!0`````!=#WI*`8`
+M`&6`)04```#]BD6./`!T8#P&=$`\$G4BOX#____H!0D``&6`#00````!9?8%
+M``````%T!>GP!0``PSP"=`7IY@4``/9%BT!T!>G;!0``@$V+0.O.98`-!```
+M``)E]@4``````G339L=%D`$`QD6.`+@^0```.460?5N_@/___U?H"#$``%^R
+M`[``Z*80``"`O7#_____=1EE@`T$````(("];_____]U"&6`#04````",<"_
+MA/___^@).P``=`^_@/___^BH/```Z5L%``")19#&18X!Z4\%``"_N/___^@3
+M.P``OY3____H"SL``('A_P```/EJ09SK%U&<L0'HTSL``)V<$,D(3;NQ`NC.
+M.P``BD6+),"(19:Q`NC,.P``L,"*9;N=<@K!X!#H3````.L8]M3!X!`!192+
+M1;SWT!%%F(M%P/?0$46<6>*MT-D(3;IFBT6Z_L3!X!#H'````+^8____,<#H
+M6CH```I%EW0$@$VZ0+$(Z5H[``"^N/___[^4____Z;X)``!T$.AP$0``9?8%
+M``````%U4<-E@"4%````_8I%CCP`=0B`?8P`=27K3SP&=0B`?8P`=1GK,CP!
+M="D\$G0//`)U!>ER_O__@'V,`'06Z.L0``!TOK^X____Z#\'``#IBP```.GC
+M_O__Z,(0``!TH[^`____Z%#M__^!;9#_/P``]T60`0```'0%_TV0ZPZQ`3#`
+MOX#____H6"\``(M%D-'X!?\_``")1<CHHO[__S'`B47$O[C____HV`\``.CI
+M#@``O[C____H'2\``("]</____]U&66`#00````@@+UO_____W4(98`-!0``
+M``*_N/___^FL`P```,2=:/___S'`B40]!(A$/0@FBP.)1#T)P?@7B&0]#"7_
+M````QT6H`````'5$BD0]"V8+1#T)=0K&1#T.`8E$/1##QD0]#@;&1:K_9?8%
+M``````)U`</'1#T0@3\```^]3#T(@^D?]]G39#T(*4P]$,,\_W4RQT0]$/]_
+M``#W1#T(____?\9$/0X*=!KV1#T+0'4.QD6H_V7V!0`````!=`7&1#T.`L/&
+M1#T.``6`/P``B40]$(!,/0N`PQ[%G6C____&1#T$`(L#B40]!8M#!!^)1#T)
+MP?@49IF(5#T,)?\'``#'1:@`````=6B+1#T$"T0]"'4%Z3W____&1#T.!L9%
+MJO]E]@4``````G4!P\=$/1`$/```#[U,/0AT%XM$/02#Z1_WV0^E1#T(TV0]
+M!"E,/1##BT0]!`^]R(/I'_?9T^")1#T(QT0]!`````"#P2#KW&8]_P=U.\=$
+M/1#_?P``@60]"/___P^+1#T("T0]!,9$/0X*=#GV1#T+"'4.QD6H_V7V!0``
+M```!="G&1#T.`NL.!0`\``")1#T0QD0]#@"+1#T$#Z1$/0@#P60]!`.`3#T+
+M@,,>Q;5H____%@>#QP17C7P]`+D"````\Z5FBP9?'V:9B%0]""7_?P``B40]
+M#,=%J`````!T+_9$/0>`=02R$NL(9CW_?W0)L@"(5#T*,<##L@J+1#T$)?__
+M_W\+1#T`=.BR`NODBT0]!`M$/0"R`738L@;KU'(9``"#&0``FAD``+`9``"C
+M&0``]!8``*X7```H'```-QP``(H<``"K&```*!P``"@<``"X&0``@'PU``=T
+M(C';B5P]`(I<-0'!XP(N_Z,?&0``BEPU`,'C`B[_DS,9```QP,/H/0T``.@4
+M`@``="&)WAX/J!_I&/___^@F#0``9D#KY>@=#0```H5U____Z]CHXP,``&9`
+MPQ[%M6C___\6!XU]EKD%````\V:E'V:!?8K__W4+OX#____HN0,``,.*19]F
+MF(AEC+^`____Z'8V``"Q$E&Q!.A4-P``@V6?#^A6-P``OH#____H..C__[$"
+MZ#$W``"+1;AF,<`!18"+1;P1182+1<`118@QP(I%GV8!18*P`!%%A!%%B%GB
+MM;^`____Z`HV``!U"(E%D,9%C@'#QT603D```+^`____Z'XW``#&18X`P[\:
+M``!,&P``LQH``+\:``!3&P``=!#H[PP``&7V!0`````!=0'#GW4(98`E!0``
+M`/V_@/___[Y\____#[9<-0'!XP(N_Z-I&@``Z`T,``!F0.F?````G@^%@0``
+M`.C/````=!KHL@P``&7V!0`````!#X2Y````Z+,"``#K8(M%J`G`=%D(P'0=
+M98`-!`````%E]@4``````0^$D0```(!,/0M`ZS@(Y'0498`-!`````1E]@4`
+M````!'1TZR!E@`T$`````F7V!0`````"=&"`O7;___\!=P7&1#T.`.A+#0``
+MZ'0+``#K"^AM"P```H5U____@^`'B<&*1#T.Z/D,``"-=#T$OQP````!S\'A
+M`@'/N0(````/J`<>%A_SI8HF9B4`@&8+1@0?969EB0?#Z"8+``!F2"0'Z"L+
+M```\`\.-=8"-?93H[@X``(!]C@!U%L=%I/\_``"+19`M_S\``+^`____ZVZ`
+M?8X&=23&1:K_9?8%``````)T(+^4____Z-3G__^+1:3'1:3_/P``Z\J`?8X!
+M=`7&18P`P\9%J?]E]@4`````!'3QQT60_W\``,9%BX#'18S_``H`P\2=:/__
+M_V8FBP,/O\#K"<2=:/___R:+`XG",<")1#T`B40]!`G0=1*)1#T(B$0]#,9$
+M/0X!B40]$,.9B%0]#'D"]]@/O<B#Z1_WV=/@B40]"+@>0```*<B)1#T0QD0]
+M#@##'L6U:/___Q8'5XU\/02Y`@```/.E7Q^+1#T(F8A4/0Q"=13W5#T$@T0]
+M!`'W5#T(@U0]"`#K$`M$/01U"HE$/1#&1#T.`</'1#T0/D````^]3#T(=!>+
+M1#T$@^D?]]D/I40]"--D/00I3#T0PXM$/00/O<B#Z1_WV=/@B40]",=$/00`
+M````@\$@Z]SHQ@P``.@%````Z3P,``"Q!>B9"0``'@^H'_;A9KDH`&8IP;X<
+M````5I@!Q@'&#[?)\V:E9HG!7O-FI1_#Z%X+``"Q!>AF"0``'O;AN2@```!F
+M*<&_'````%>8`<<!Q\6U:/___X/&#H!]^`%U`X/&#O-FI6:)P5_S9J4?Z54+
+M``##,<")1#T$QT0]"````,#&1#T,_\=$/1#_?P``QD0]#@+#=`_HLPD``&7V
+M!0`````!=.YE@R4%````_>C#_/__,<"?OY3___^^?O___^F[_/__=!)E@`T%
+M````066`)04```#YZTME@"4%````N(I%CCP2=#P\`G0@/`IT%#P&=0IE@`T%
+M````1.LF]D6+@'0(98`-!0````30R',(98`-!0```$#0R',(98`-!0````'V
+M18P!=`AE@`T%`````L-T(>@5"0``9?8%``````%T1K^4____Z";___\,_Y_I
+M8/___^@;_?__=`7I4?___V6`)04```#]QT6H`````(I%CCP2=1]E]@4`````
+M`74)98`-!`````'#OX#____HW_[__^L8/`)U+?9%BT!U$F7V!0`````!=->`
+M38M`QD6H_XUU@(U]E.C""P``Z+/[___IZ_[__^BZ_/__Z=3^__]T$.AV"```
+M9?8%``````%U!</&18P`Z8'[__]T$.A;"```9?8%``````%U!,/V58SI9_O_
+M_P!0L0'H>S$``+$!Z&LQ``"^E/___[^X____9L=$-0```+D#````N``````;
+M1#4`B40]`$9&1D9'1T='XNGK%%'HZS$``+Z4____]H5H____`70%OKC___^_
+M@/___^@F````T)5H____6>+4]H5H____`74/OI3___^_@/___^@%````Z:@Q
+M``"+1#4`9C'``40]`(M$-0011#T$BT0U"!%$/0C#`>\![AX6'Q8'N0,```#S
+MI1_#GV6`)04```#Y9L>%:/___P``GG0*Z'@'``#IY@$``(I%C@I%H@^%S@$`
+M`(M%D"M%I+^`____?&.#^#]^#F6`#04````$@\@@@^`_*4600.CW_O__,<"_
+MA/___^CV+P``=1EE]@4%````!`^$&@$``(B%:/___^D/`0``OX#____H?#$`
+M`&7V!04````$=`S&A6C___\`Z;@```"?@+UT____+@^%J@```)YU![$!Z+PP
+M``#_3:3_=8S&1:``QD6,`,:%=/___P:+19`[1:2^@/___WX%OI3___^_X/__
+M_^@*____Z'@0``"_N/___^A_+P``CT6,OX#___]U%/:%:/___P%T3?Z%:/__
+M__95C.M"ON#___^`?<0`=`SHS?[__[^`____ZRN+19`[1:1T"K^4____Z+3^
+M___^A6C_____1:2*18R(1:#H$Q```+^X____@WP]$`%]88G^Z`7A__]E_S4`
+M````98`-`0````/&A7#___\`Z-7A__]ECP4`````O[C____K,8E%D,9%C@&`
+MO73___\N=1S&18P`9?8%`0````1T#F7V!0$````(=03&18S_OX#___^^?/__
+M_^C^^/__98`E!0```+R*A6C____`X`9S"&6`#04````!T.!S"&6`#04```!`
+MT.!S"&6`#04````"PZ@0="9E@`T$`````67V!0`````!=.F_@/___^B>^___
+MOGS____I"N3__XI%HHIECH#\`G0&/`)U*>L*]D6+0'0*/`)U&/9%GT!U$F6`
+M#00````!9?8%``````%THNERX___@+UT____&`^$K0```(#\"G20/`%TC(#\
+M!G5C98`-!`````)E]@4``````@^$;/___[^`____/`IU/?9%BX!T$,=%D`$`
+M``#&18X`Z6[___]E]@4`````$`^%8/___^@EX?__@460`&```&6`#00````0
+MZ4?___]0Z`OA__]8/`9U(F6`#00````"9?8%``````(/A`7___^_E/___U#H
+MY>#__UB`_`$/A*[^__\\"@^$IO[__^D6_?__@/P*=6B`?8P`=2X\`0^$U?[_
+M_SP&=1)E@`T$`````F7V!0`````"=%N*1:"(18R_@/___^G_````/`H/A*?^
+M__\\!G4298`-!`````)E]@4``````G0MOY3____H$2T``(E%I,9%H@'IRP``
+M`(#\!G4398`-!`````)E]@4``````G4!PSP&#X6F````98`-!`````)E]@4`
+M`````G3E@/P`=0R_E/___^@@X/__ZR]E]@4`````$'5YZ90```!T"NBW`P``
+MZ27^__]E@"4%````_8I%C@I%H@^%!?[__V7_-0````!E@`T!````#.B+"P``
+M98\%`````'0(@'V,`'0,ZQB+18@]/>```'X'N#W@``#K##T"(/__?06X`B#_
+M_P%%I(%]I/Y_``!_%8-]I`%\(+^4____OGS____I;/;__[Z4____Z`7>___H
+M$][__^LLOI3____H]-W__V7_-0````!E@`T!`````\:%</___P#HQ-[__V6/
+M!0````"_N/___^NRATP]!B')>0+VUH'A____?PM,/0)F"TP]`'0"]M(PY/9$
+M/0H!=!'VU,=$/0(`````9L=$/0```+D"`0``PX9,/0@@R7D"]M:`X7\+3#T$
+M"TP]`'0"]M(PY/9$/0D!=`+VU,=$/00`````QT0]``````"Y`P$``,.'3#T$
+M(<EY`O;6@>'___]_"TP]`'0"]M(PY/9$/0@!=`+VU,=$/0``````N00!``##
+MBTP]!/;%!'0"]M:!X?\#```+3#T`=`+VTC#D]D0]!0AT`O;4QT0]``````!F
+M@60]!`#XN0<(``##ATP]`"')>0+VUH'A____?W0"]M(PY/9$/00!=`+VU+D(
+M`0``P[DD``#S)```)"4``%TE``!\)```"B8```(F````)@``,28``##V#[_R
+MP>8"9C'2,<DN_Y:")0``9B'2=1L\_XC0=0>(A7'____#9HF5</___XB%;___
+M_\,\_W4(B(5Q____ZPEFQX5P_____P!0Z+4````/MMA8+O^CEB4``/;7.'P]
+M#'4SZR>(UPCB//]U&XJ=</___V:!^_\`=0XZI6____]U!F9"=`;K#F9"=`JP
+M`(B%;____^LHQH5O_____XCJ,.V[#````"G+`=\PP`!4/0!'21!$/0!'XOD8
+MP(/O#,.(Q.@_````/`1U!R#D=`LPP,,\"'7Y(.1T]0S_P^@D````/`1T]#P(
+M=/#KX[(#92(5`0```,-E@"4!````_&4(!0$```##966*!0$````D#,-E@"4!
+M````\V4(!0$```##966*!04````D.,#H`\,/ML")P='AB<O!XP(!RX/#'&5F
+MH0@```!FT^@D`SP"=2QE9F6+0PAF)?]_=0.P!L-E98M#!*D```"`=0.P$L,E
+M____?V4+`[`*=`*P`L-E]@4`````$,/HB@```&7V!0`````"P^AS````9?8%
+M``````'#9?8%``````C#9?8%`0```!##9?8%!````"##9?8%!`````'#9?8%
+M!`````+#98`-!````$%E@"4%````_<-E@`T$````066`#04````"PV6`#00`
+M```@PV6`#00````0PV6`#00````(PV6`#00````!PV6`#00````"PV6`#00`
+M```$9?8%``````3#98`-!0````'#98`-!0```$##98`-!0````+#98`-!0``
+M``3#98`E!0```/[#98`E!0```+_#98`E!0```/W#98`E!0```+C#98`E!0``
+M`/O#98`E!````-_#Z`O___]U!^@H____=7J*A7C____H!@```(J%>____SP!
+M=#DT`'4TZ&S^__\"A77___\D!XC!L`/0X69ETPT(````98`E"````/PD`V4(
+M!0@```!F9=,%"````,/H-_[__^C.____L0CK`K$X966*!04````D.&4P!04`
+M````R"0X90@%!0```,,>#Z@'Q;5H____OP````"Y!P```(!]^`%U#?.E'V6`
+M#0````!`ZP]FI4='XOH?98`-`````$"Y"````#';N`H```#WX[X<`````<:X
+M`P```&4C!0@```"#^`-T0F5F98M&"&8E_W]T&67V1@>`=02R`NL<9CW_?W0$
+ML@#K$K("ZPYE98M&!&4+!K(!=`*R`F6`)0@```#\90@5"````&9EP0T(````
+M`D/BD\-FN'\#96:C`````&:X__]E9J,(````9D!E9J,$````P\2=:/___V8F
+MBP-F#4``96:C`````,/H10```&6`#0````!_PV5EQ@4$`````,.*A7K___\\
+M!&5FH00```!T"\2=:/___V8FB0/#9HE%+,-E9J$`````9B5_'V8-0!#KWQX/
+MJ!]F98$E`````'\?9F6!#0````!`$+X`````Q+UH____N0<```"`??@!=03S
+MI1_#9J5&1N+Z'\,`2RP``,\M```++P``Q"\``(DP``"R*@``"R\```LO``#F
+M*@``=`_H+/W__V7V!0`````!=&!E@"4%````_8"]??___P1U"N@S\/__Z<']
+M__\/MIU\____P>,"@_L(?2*`?8X2=1QE@`T$`````67V!0`````!=!Z_@/__
+M_^C[\O__+O^C'"H``!X6'Q8'N04```#SI1_#Q+UH____'A8?C76$N0(```#S
+MI1^*98QF)0"`9@M%D&8FB0?I4_W__P```````$!V.FL+WF7_-0````!E@`T!
+M`````X!]C@%U!>D?`0``@7V0_W\``'4P98`-!`````%E]@4``````74%Z2,!
+M``#'18(`````QT6&````@&;'18K__^GO````@'V.!G4+QT60`0```,9%C@"X
+M/D```#E%D'VUOX#___]7Z)\:``!?L@.P`.@]^O__,<"_A/___^C")```=0F)
+M19#&18X!ZWV+5#T$@?JSMN`-#X=Y____BT0]`'(+/0``9*</@VC____'1#T$
+M`````,=$/0``````@^\"NP#*FCOW\U"Y!````+MD````B=`QTO?SDM0*P.0$
+M"."(1#T`1^+K6`G`B%0]`'094C'2N0H```#W\9)9B,2(R&H`N04```#KTH"]
+M</____]U&66`#00````@@+UO_____W4(98`-!0````**98R`Y("(98MEQ#T4
+M````'A8?C76"N04```#S9J4?Z.K[__]ECP4`````PV@M*```Q+UH____OH$_
+M``"R`(I%CCP`=$0\!G0V/`)U'/9%BT!U%F6`#00````!9?8%``````%T&8!-
+MBT"+38F!X?__?X`/MD60P>`7"<@FB0?#OX#____H'-?__[]^0```Z$(```#$
+MO6C___]T+7@DBT6))?___X"I____`'01)?__?X`/MDV0@,&`P>$7"<@FB0?#
+MN'___W_K!;A_``"`"D6,P<@(Z^A75E*P`+^`____Z*/X___HW!@``%I>7SEU
+MD'Q1#X2(````.7V0#XZ)````98`-!`````AE]@4`````"'4#6%C#98`-!```
+M`"!E98H%`0```"0,M`@XQ'@4BD6,Z!#Y__^<>`AE@`T%`````IW#9?8%````
+M`!!U"F6`#00````0Z[R_@/___XGP5U+H>Q@``%I?L/_H&OC__V:#O7#___\`
+M=`AE@`T$````,/9%BX!U!&;_39!F@[UP____`'0998`-!````""`O6______
+M=0AE@`T%`````C'`0,-H+2@``+X!/```L@**18X\`'1#/`9T-3P!=0AFQT60
+M`#SK4CP"=1WV18M`=1=E@`T$`````67V!0`````!=0'#@$V+0&;'19#_0^LI
+MOX#____HG]7__[_^0P``Z,7^__]T?7AHBD6%9IB_AO___^CZ(0``=#NQ`^AD
+M(@``Q+UH____'A8?C76%N0,```#S9J4?9HM%D&8M`#QFP>`$@&6+#PI%BX!E
+MC(`*98QF)HD'PS'`Q+UH____)HD'9B:)1P2*98R`Y(!F)HE'!L.X_____^C<
+M____9KCO?PIEC.OGZ,S___]F)H%/!O!_P[D.0```*TV0>$6#^1%V!;D1````
+MOX#___\PP.@4%P``OX#___^R!+``Z+WV__\\`'4=9H%]B@"`<@AW$X!]C/]U
+M#;``.D6,=`9F]UV*,,##@'V.`'0&@'V.!G4]Z)____]U-F:#O7#___\`=!EE
+M@`T$````(("];_____]U"&6`#04````"9HM%BL2]:/___V8FB0?IV?C__V8Q
+MP(!]C@%TZ&6`#00````!9K@`@&7V!0`````!==+#N1Y````K39!X18/Y(78%
+MN2$```"_@/___S#`Z%L6``"_@/___[(!L`#H!/;__SP`=1V!?8@```"`<@AW
+M$H!]C/]U#+``.D6,=`7W78@PP,.`?8X`=`:`?8X&=3OHG____W4T9H.]</__
+M_P!T&66`#00````@@+UO_____W4(98`-!0````*+18C$O6C___\FB0?I(OC_
+M_S'`@'V.`73J98`-!`````&X````@&7V!0`````!==/#N3Y````K39!X4X/Y
+M078%N4$```"_@/___S#`Z*05``"_@/___[(#L`#H3?7__SP`=2N!?8@```"`
+M<@YW((-]A`!U&H!]C/]U%+``.D6,=`TQP/==A!M%B(E%B##`PX!]C@!T!H!]
+MC@9U0NB1____=3MF@[UP____`'0998`-!````""`O6______=0AE@`T%````
+M`HM%A(M5B,2]:/___R:)!R:)5P3I5O?__S'`F8!]C@%TY66`#00````!N@``
+M`(!E]@4``````77.PXM%@&8QP`-%E(E%N(M%A!-%F(E%O(M%B!-%G(E%P+``
+MT-##BT6`@664``#__RM%E(E%N(M%A!M%F(E%O(M%B!M%G(E%P+``T-##ON]%
+M``#K!;Y/,@``BTV0*TVD>"F#^4-V!;E#````L`"_E/___U;_UEZ+19")1<B`
+M?8X!=#/V18N`=2WK'??9@_E#=@6Y0P```%&P`+^`_____]:+1:2)1<A9@'VB
+M`70(L`#V19^`=`*P_X"]=/___P9U`_95H(IEC#IEH'4HZ#/___^_N/___^@5
+M%```BD6,B$7$]D7#@'4,O[C____H;AX``'5=PU"*18R(1<3H)____[^X____
+M/`"X`````'0<]U0]`(-$/0`!]U0]!!%$/03W5#T($40]"/95Q.@P'@``=1KH
+M@/3__S0$9DAFF(AEQ%@\_W469L=%R```PU@\_W4*O[C____HE!\``,/H8AX`
+M`(M$/0`E____'PG"=`B!3#T`````((%D/0````#@PW0598`E!0```/UE@`T$
+M````0>DH`0``QT6H`````&6`)04```#Y@+UT____*745QD6@`,9%H@&_E/__
+M_^BU'0``B46DBD6."D6B='8\`71RJ!`/A=\```"*18Z*9:(\`G0'@/P"=2WK
+M#_9%BT`/A,0```"`_`)U"O9%GT`/A+4```"`O73___\O#X3)````Z:,```"`
+M?8X&=1'&1:K_@WV0`'4'QT60`0```(!]H@9U$<9%JO^#?:0`=0?'1:0!````
+MQH5T____!N@"_O__O[C____H"1T```^$A````&6`)04```"^]D7$`70(98`-
+M!0````&#?:@`=07IO/3__X!]J`!T&V7V!0`````!=`7II_3__\.`?:H`=07I
+MF_3__V6`#00````"9?8%``````)TXNF$]/__98`-!`````''1:C_````ZQ"`
+M?8X&=`:`?:(&=03&1:K_98`-!0````7K"&6`)04```#^98`-!0```$#K@```
+M@`````````````"```````````````````#U'YCLP+OP%UPI.ZJX````````
+M``````$```````````#``(1DWODS\P2U````C?01!5^L?XH```````````"`
+M`/________^_`*"?A];[.1K`E0!@\E?<:%["TZ0`(/T\M-[/T0"N`(#FLYA(
+MUK<?LP#`B3GL=ZR;UK4`@%-,D18NM#RW`(#\BT)XMX7RMP#@5KICU6LC3K@`
+MX#$FJU/X'WRX`&#]H*(?NBF3N`#`5QB^RGNQGK@`H'!$_@T5=J2X`&"J&YO2
+MCUBGN`!@E.F:OMC)J+@`@#-R)1>`@JFX`,`TPF@AHMH/R0"`17O:#2LX8^T`
+M8!7K!F3)K]OZ`,`R;GMAU=2M_@#`-D[O9[G=JO\`@$(EL4O=K>K_`."[U93;
+MW:KZ_P``:+G4W:VJ_O\`P$NYW=VJJO__`*!+W=VMJNK__P"@V]W=JJKZ__\`
+MX-W=K:JJ_O__`.#=W:JJJO___P#@W:VJJNK___\`X-VJJJKZ____`."MJJJJ
+M_O___P#,.0``LSD``+`Y``"G.0``%CD``*1!``"J00``03H``#0\```)/```
+M!SL```D\``!`/```"3P``/,[```T/```-#P``$$Z```>/```XCH``!X\``#S
+M.P``LSH``$$Z``#W/```P#P```<[``!;/```)#L``-\\``!;/```KSP``"0[
+M```#/0``F3P``.(Z```-/0``#3T``+,Z``!!.@``.ST``#L]```'.P``63T`
+M`#L]```D.P``0ST``*\\```D.P```ST``)D\``#B.@``)3T``"4]``"S.@``
+M9?\U`````&6!#0```````P``98`-!````"#&1<0`9L>%;/___P``BT6D*T60
+MB46H@_@/?C^#^#]_!>G0````Z!#<___H*`\``(M%R(/X``^/!0(```^,`P(`
+M`+^\____Z'09```/A?,!``#&1<8!Z>H!``#HS1D``.C1&0``Z#KZ__]FT:5L
+M____@'W#`'54Z$8;``"_@/___^B7&0``Z/;Y___H1QL``+[H,P``Z&X;``#H
+M,1L``(%EE````/_H"QL``&;_A6S___^`?<,`=!.Y`0```.AM&0``@664````
+M_^L%Z!0:``#_1:B#?:@/=HRY!P```.@#&@``@66`````X,=%J`\```#HX1D`
+M`.@&V?__Z-<:``"Y"0```.@N&0``@66```#@_^BZ&@``Z!(9``"!990``.#_
+M@66X````X.B4&@``Z$[Y___HD1H``.AY&@``Z&T:``"Y'@```.CL&```QT6`
+M`````+D>````Z(D9``#H)=O__[^X____Z+$8``#&1</`Z%L:``"!990```#@
+M@'WW`+`!N0<```!U![``N0@```!0O^[____H4!D``.@#&@``Z%S8__^!9;@`
+M``#@6-#HN0<```!S!;D&````Z&88``#H$AH``&;1K6S___]S&;@*````]V6H
+M!>(T``")QN@F&@``Z/`9``!F@[UL____`'06N0$```#H/1@``(%E@```X/__
+M3:CKOH!]BP"Y"````'0(N0<```#_3:CHQQ@``,=%D/X_``"+1:@I19"_@/__
+M_^@5&0``Z$09``"+19")1<C&1<8`98\%`````,/'1#T``````,=$/00`````
+MQT0]"`````#'1#T,```!`,=$/1``````P\=$/0``````QT0]!#7":"''1#T(
+MHMH/R<=$/0P`````QT0]$/\_``##BE6,BG6@QD6,`,9%H`"(\X/C"(M%I#M%
+MD'\W?"N+18@[19Q_+7PABT6$.T68?R-\%[^X____Z)S_____3<@)VP^$LP``
+M`.LX4^@7$@``6X/+!%-2Z._\__]:6PG;=2&+1<B#^`!_3WP&@'W&`71G4NBG
+MR?__6F6`#00````0ZWF_@/___^A-____+O^C@C4``,:%=/___P7K"O]%D,:%
+M=/___P92C7V4C76XZ-[P___H=_?__UIE_S4`````98$-```````#``!2Z.L+
+M``!:98\%`````&:#O7#___\`=!EE@`T$````(("];_____]U"&6`#04````"
+MB%7$PW07Z%GM__]E]@4``````74!P^CVQ___ZWAE@"4%````_0^V78X*7:(/
+MA=X````/MIUT____@.L4=%"`^_QT/(%]D/\_```/C\4```!\)H!]C``/A+D`
+M``"!?8@```"`#X6L````@WV$``^%H@```.G4`0``NP@```#K#X!]C``/A8P`
+M``"[!````"[_DY(U``"_N/___[Y\____Z5O+__]E@`T$`````F7V!0`````"
+M#X1;____OX#____H\<C__[^4____Z.?(___I7____V6`#00````"9?8%````
+M``(/A"S___^_@/___^C"R/__Z3K___]E@`T$`````F7V!0`````"#X0'____
+MZ[3VPQ!T&V6`#00````!9?8%``````$/A.K^___IYO[__X!]C@)T"(!]H@)U
+M+^L,]D6+0'0,@'VB`G4<]D6?0'4698`-!`````%E]@4``````0^$K_[__^DT
+MRO__BGV.#[:%=/___RP4=$$\_'0I@7V0_S\``'P9#X3&_O__@7V0_W\``'6`
+M@'V,``^%=O___[B`````ZQ2`?8P`=`F`_P$/A6#___^X0````(I=HO;'!'0"
+MMP/VPP1T`K,#@>,#`P``P.<"`/LP_\'C`@'#+O^CGC4``&6`#00````"9?8%
+M``````(/A!O^__^`?:``=#>_N/___^C4_/___T7(ZS)E@`T$`````F7V!0``
+M```"#X3P_?__O[C____HK_S__^L0@'V@`'7)O[C____H=/S__XI5C(A5Q.E)
+M_O__98`-!`````1E]@4`````!`^$L_W__\=%B````(#'18P```H`QT60_W\`
+M`+^`____BE6@]M*(5#T,Z1#^__]E@`T$`````F7V!0`````"#X1U_?__OX#_
+M__^*5:"(5#T,Z>G]__^!?9#_/P``?SI\-8%]B````(!W+X-]A`!U*>E%_O__
+M98`-!`````1E]@4`````!`^$+_W__^L)@7V0_S\``'T#]E6@OY3____IG/W_
+M_V6`#00````"9?8%``````(/A`']___KVV6`#00````"9?8%``````(/A.G\
+M__^*58PP5:#KP&6`#00````"9?8%``````(/A,O\__^*5:`P58R_@/___^E`
+M_?__6_]T-0#_=#4$_W0U"/]T-0S_=#40_^-;CT0U$(]$-0R/1#4(CT0U!(]$
+M-0#_X\=$-0``````QT0U!`````#'1#4(````@,=$-0P`````QT0U$/\_``##
+M9L>%;/___P``N/\_```K19"#^#]_48E%D(/X#W=^Z,H2``"X"@```/=ED`5"
+M-```B<;HH10``&;1I6S___^`?<,`=1/H110``(%E@```X/]F_X5L_____T60
+M@WV0#W<PZ#83``#KO,9%H`#'1:3_/P``O@8T``#H;10``.@-$P``Z&S4___H
+MA`<``.DN`0``QT60#P```.C[$@``Z)P3``"Q'NA'$@``@V6``+$>Z.H2``#H
+MAM3__^C1$P``@66`````X+[\,P``Z!$4``"+39"#P0KH!!(``(%EN```X/_H
+MB!,``.@#$@``Z)@3``#H9_+__XM-D$'HX!$``(%EN```X/_H?A,``+X&-```
+MZ+83``#H51,``.AJ$P``Z&P2``#HD='__[D(````Z*P1``"!9;@``.#_9M&M
+M;/___W,DZ$@3``#H/!,``(M-D.B3$0``@664``#@_V:!39Z``.C3\?__9H.]
+M;/___P!T$>AG$0``@66X``#@__]-D.NXL0B`?<,`=`6Q!_]-D.CU$0``N/\_
+M```K19")1<C'1<0`````]D7#@'4*L0'HUA$``/]-R.C5$@``Z.T2``##]E6,
+MZ#G^__^-=;B-?93H$NO__[Z`____Z/O]___&18S_QH5T____!KZX____Z+C]
+M___HC/'__^@4!@``C76XC7V4Z-[J__^^@/___^BP_?__Z-W2___H]04``,/H
+M]P8``'4%Z;/:__^!?9#_/P``?_)\&H%]B````(!WYX-]A`!UX8!]C`!TV_]-
+MD.O698`-!````"!E_S4`````98$-```````#``!E@24`````__/__X%]D/X_
+M``!T"(!]C`!U6>L5@7V(````@'=5@WV$`'5/@'V,`'5"Z&3]__^+3<B#^0!^
+M!L9%Q@#K#>C#PO__98`-!````!"`O6______=0AE@`T%`````F6/!0````"_
+MN/___^D&VO__Z.'^___KO(!]C`!U?[Z4____Z.?\___&A73___\&Z(;P___H
+M#@4``(UUN(U]@.C8Z?__Z*[^__^-=;B-?8#HR.G__[Z4____Z+'\___&A73_
+M__\%Z%#P___HV`0``/]%R(UUN(U]@.B?Z?__OI3____HB/S__\:%=/___P;H
+M)_#__^BO!```Z5+___^^E/___^AH_/__QH5T____!>@'\/__Z(\$``"-=;B-
+M?8#H6>G__^AP_/__C76XC7V`Z$GI__^^E/___^@R_/__QH5T____!>C1[___
+MZ%D$``"-=;B-?8#H(^G___]-D+Z4____Z`G\___&A73___\&Z*CO___H,`0`
+M`.G3_O__QD7:`.L$QD7:`67_-0````!E@0T```````,``+_B____Z"40``"*
+M1:*(1>*+1:2)A6C___^*1:"(1<[&1=@`@'W:`'4HZ+\.``"^)#0``.B@$```
+M@'W#`'5<Z5P!``#H[@\``,9%V/_IBP$``(M%D(E%R(!]C`!UYNCE#P``N?\_
+M```K39"#^4AV!;E(````Z&T.``!FBTV6@>'_'P``"<IT!F:!398`((!-GX"!
+M990```#@ZSOH^`X``.B2#P``N0$```#HV0X``+^Z____Z+H-``!T.,=%R/X_
+M``"_N/___^A7#P``Z'</``#HN0\``/^U:/___^C8S?__CX5H____@66X````
+MX.G4````Z/38__^_@O___^AQ#0``=1?&18X!BD7.,$6,C76`C7VXZ,SG___K
+M;X%EX````/_H0`\``(N%:/___XE%I(I%SHA%H.C>S___Z-`"``"+1<@]_G\`
+M`'](@_@`?$I_$K^\____Z!T-``!U/,9%Q@'K!,9%Q@!F@[UP____`'0998`-
+M!````""`O6______=0AE@`T%`````F6/!0````##Z`2____K\>C5O___Z^K_
+M19#HH`X``+X0-```Z!@/``"Y!P```.C,#0``QD78_\=%R/\_``"_NO___^BB
+M#```=`J_N/___^A&#@``Z*8.``!FQX5L____``"X_S\``"M%R(E%J(/X#P^'
+MD````.B+#@``N0<````#3:CHWPP``.C/#```Z![M__^`?<,`=!F!9;@``.#_
+MQD7#`.A7#@``9L>%;/___P$`9M&E;/___^CE#0``BTVHZ*(,``"!38@``(``
+MZ-_L__^`?<,`=!>!9;@``.#_QD7#`.@8#@``9O^%;/___[D!````Z!`-``#_
+M1:B#?:@/=K#H``T``&6`#00````@Z(\-``#HGL[__XM-J(/Y2'8%N4@```#H
+M*PP``(%EN````.#HR0T``.B8[/__Z+@-``"+3:B#^4AV!;E(````Z!4,``"!
+M98````#@Z&$-``"^&C0``.C9#0``Z)D-``#H60T``(M-J$&#^4AV!;E(````
+MZ-D+``"!990```#PZ$+L__^!9;@```#@Z#4-``#H70T``/^U:/___^B#R___
+MCX5H____@66X````X.A'#0``OBXT``#HC@T``+D'````Z((+``#_3:AFT:UL
+M____<R*+=:A.N`H```#WYHG&@<9,-```Z&H-``#H"@T``.BOZ___9H.];/__
+M_P!T"NA#"P``_TVHZ\&X!T```"M%J(E%R(%EN```X/^_N/___^C:"@``=`J_
+MN/___^A=#```@'W:`'4XZ!O6___HL@P``(M%R(E%I,:%=/___P6*1=B(1:#H
+MG.O__^B<#```BD7$B$6,BT7(B460Z?3\__^*1=B(1<3KXL9%N@&R`[^X____
+ML`#HR=___[^X____M`2H`74!P_]$/1"Q`>C""@``(=)T!8!,/0(!PXG!AT0]
+M$"G!@_E#?@6Y0P```##`Z]MT*NA8X?__98`E!0```/ME]@4``````74"6,._
+M@/___[Y^____6)_I9-3__V6`)04```#[Z$W5__]T!#'`Z]S'1:@`````98`E
+M!0```/V*18X\`79M/`9R#G0_OX#____H']?__^L*]D6+0'7.@$V+0&7V!0``
+M```!=0IE@`T$`````>N4C76`C7V4Z`#D___&1:C_6.D<U___9?8%``````)U
+M#66`#00````"Z6C____&1:K_OX#____H\;S__X/(`<-T'^B5X/__98`E!0``
+M`/ME]@4``````74"6,-8Z:+3__]E@"4%````^8I%CCP!?FL\!GPJ=$:`O73_
+M__\2=1,\$G0/@'V,`'32QT60_S\``.O)OX#____H9=;__^L*]D6+0'6W@$V+
+M0&6`#00````!9?8%``````%TG^N?98`-!`````)E]@4``````G2+OX#____H
+M5;S__X/(`<,QP(J%=/___XIEC(E%K,9%C`!FQX5H____``"+19`M_C\``'Q5
+M@_@_?@IE@`T%````!%C#QT68-<)H(<=%G*+:#\G'1:``````QT6D_C\``"E%
+MD$#H8-?__XM%A`M%B'4/B46`B460QT6.`0```.L2OX#____H]0D``&6`#00`
+M```@]H5H____!'0$9O=5K?:%:/___P)T!O95K_95KO:%:/___P%U`</V5:^`
+M?8X!=2>`?:P3=2'&18N`QD6.`,=%D/\_``"^E/___^A4]?__@\0$Z2(#``!E
+M@`T$````(,=%E`````#'19@UPF@AQT6<HMH/R<=%H`````#'1:3^/P``QD6,
+M_\:%=/___P7HO.C__V7_-0````!E@24`````__/__^@R_?__98\%`````(UU
+MN(U]@.CUX?__PV;'A6S___\``(E%D(/X$']8_TV0Z.0'``"X"@```/=ED`7B
+M-```B<;HNPD``&;1I6S___^`?<,`=1/H7PD``(%E@```X/]F_X5L_____T60
+M@WV0#W<'Z%`(``#KO.A%"```QT6``````.C?"```Z-O)__^+39#1X8/!".AM
+M!P``@66X````_^@+"0``OD(T``#H0PD``.C;"```Z%0'``#HV`@``+$)Z%,'
+M``#HV`@``.B2Y___Z#`'``#HT`@``/]-D&;1K6S___]S-NBL"```Z(T(``#H
+M;>?__^BP"```BTV0T>'H#`<``(%EE```X/_H=>?__^B."```@67@````_V:#
+MO6S___\`=!BQ`;_L____Z.P&``"!9>P``.#__TV0ZY^Q"(!]]P!T!;$'_TV0
+MO^[____H=P<``.@J"```N/\_```K19")19"_@/___^C=!P``Z!P(``#H/P<`
+M`,=%I/\_``#'1:``````OY3____HNP<``,/HY_O__W4/OI3____H7O/__^F,
+MT___Z##]__^`?8X!=2^`?:__=>#'18``````QT6$`````,=%B````(#'18P`
+M``H`QT60_W\``,9%J?_KM[C_/P``*T60@_@_?GP]_S\``'Q`BD6MB$6,98`-
+M!````!!E]@4`````$'4)@460`&```.N"OX#___^X`0```.A"^___QT60````
+M`,9%C@;I8____[Z4____Z,'R__^`?:__#X6-````9HM%K8A%C(AEH&7_-0``
+M``!E@0T```````,``/]UK.LP9?\U`````&6!#0```````P``_W6LZ)7]__^/
+M1:QFBT6MB$6,B&6@_W6L@'VO_W4'Z&4```#K!>AC````@+UO_____W4(98`-
+M!0````*-=;B-?8#H2]___[Z4____Z#3R__^/1:QECP4`````BD6M,D6NB$6,
+MZ5?2__^^@/___^CD\?__C764C7V`Z!3?__^^E/___^CF\?__P^C;____9?\U
+M`````&6!#0```````P``Z/O&___H$_K__V6/!0````##OKC____HF_'__^C-
+M____C76XC7V`Z,;>__^^E/___^B8\?__98$-```````/``#&A73___\%Z$/E
+M___HR_G__XUUN(U]E.B5WO__OH#____H?O'___]%D.A_____P^BP^O__=1K&
+M1:PKBD6,B$6MC76`C7VXZ&;>___IG0$``.@K^___@'V.`74+@'VO_W7?Z7T!
+M``"`?:__#X38`0``N/\_```K19"#^!Y\5'\1@7V(```0C7=)<K:#?80`=+`]
+M_S\``'RI98`-!````!!E]@4`````$'4)@460`&```.N.OX#___^X`0```.A*
+M^?__QT60`````,9%C@;I;_____]UK&7_-0````!E@24`````__/__V6!#0``
+M`````P``0.C&^___OH#____H=?#__[Z4____Z&OP___HF/[__[Z4____Z'/P
+M__^^@/___^AI\/__Z*C^__]ECP4`````CT6L98`E!0```/V`O6______#X6E
+M````98`-!0````+IF````(UU@(U]E.A1W?__Z(#%___H<OC__XUUN(U]@.@\
+MW?__OI3____H)?#__\:%=/___P7HQ./__^A,^/__C76XC7V4Z!;=__^^@/__
+M_^C_[____T60Z`#^__^-=;B-?93H^=S__[Z`____Z.+O___&A73___\&Z('C
+M___H"?C__\/H"_G__W4MQD6L+,9%K@"^N/___^BW[___@'VL+'0%BD6MZP.*
+M1:Z(1<2_N/___^FDS/__Z'/Y__^`?8X!=2N`?:__=<K'1;@`````QT6\````
+M`,=%P`````#'1<0```$`QT7(`````.NZ@'VO_P^$*/[__[C_/P``*T60@_@^
+M?!5_C(%]B````(!W"H-]A``/A'G_____=:QE_S4`````98$E`````/_S__]E
+M@0T```````,``$#H+?K__^@3_?__C76XC7V`Z!'<___HL/[__V6/!0````"/
+M1:QE@"4%````_8"];_____\/A2G___]E@`T%`````ND<____Z$OW__]U+#'`
+MBF6,B46LOI3____HNN[__X!]K_]U!>B3_/__9HM%K8A%C(AEH.G3SO__Z'?X
+M__^`?8X!=-&X_S\``"M%D(/X/GQ2?P^!?8@```"`=T>#?80`=4$]_S\``'RL
+M98`-!````!!E]@4`````$'4)@460`&```.N1OX#___^X`0```.BM]O__QT60
+M`````,9%C@;I<O____]UK&7_-0````!E@24`````__/__V6!#0```````P``
+M@_@>?!]_$8%]B```$(UW%'(&@WV$`'4,,=N^@/___^C$[?__G$#H!/G__YUT
+M%+Z`____Z+#M__^^E/___^BF[?__G.C2^___G704OI3____HJNW__[Z`____
+MZ*#M__^^N/___^A_[?__=`><Z-+[__^=OH#____H@^W__W0*OKC____H8.W_
+M_^@Z_?__OH#____H:.W__XUUN(U]E.B!VO__98\%`````(]%K.FK_O__9HM$
+M/0AF"T0]!F8+1#T$9@M$/0)F"T0]`'4!PV:X___#BT0]``M$/00+1#T(=0'#
+MN/_____#,<")1#T`B40]!(E$/0C#9C'`9HE$/0AFB40]!F:)1#T$9HE$/0)F
+MB40]`,.+3:C0X>L9L0&_N/___^L0L0B_E/___^L'L0B_@/___[``,=+0R`^^
+MP%"U`H#Y(')9@/E@<B%T`V8)P@M4/0`+5#T$"U0]"(C@B40]`(E$/02)1#T(
+M6,,>%A\6!P'OB?Z(RX/A8,'I!8C("Q:#Q@3B^6:Y`P`HP8C/\Z6(P8C@\ZN#
+M[PPI[Q]FB=E85U"+1#T`,=L/K<,)VHM$/00/K40]`(/'!/[-=?!8B.`/K40]
+M`%_XP[^Z____ZQ2Q"+^6____ZPNQ".L"L0&_@O___X#Y4'X"L5"(R"1X=#)1
+M5QYFF&;!Z`-F2+D)`````<\/O\`IP0'OB?XIQDX6'Q8'_?.DB`^)P8G^3_.D
+M_!]?68/A!W0;9M%D/0!FT50]`F;15#T$9M%4/09FT50]".+EP_9$/0N`=1A7
+MN0$```"#QP+HS____U__3#T0]D0]"X##Z-O___]T^<._@O___[Z6____ZV*_
+MNO___^L/O^+____H!0```+^6____OH+____K1;^6____ZP6_@O___[[N____
+MZS*_EO___^L%OX+___^^XO___^L?O^+____K$[_N____ZPR_EO___^L%OX+_
+M__^^NO___P'N'A8?%@<![[D%````\V:E'\.^\C,``.@*````O[C____I9?/_
+M_^@E````Z6_>__^_@O___^@;````Z8/>__^_EO___^OOZ`4```#I5<#__[^6
+M____'@[KJ@``!`````4`````````#P````4````8````(`````4````<````
+M+0````4```"T4@``-@```%]F<&5?<W1A<G0`7V9P95]R96=?<V5G;65N=`!?
+59G!E7W)E8V]V97(`7V9P95]E;F0`
+`
+end
diff --git a/i386/i386/fpe.b_elf b/i386/i386/fpe.b_elf
new file mode 100644
index 00000000..c04619e1
--- /dev/null
+++ b/i386/i386/fpe.b_elf
@@ -0,0 +1,576 @@
+begin 775 fpe.o
+M?T5,1@$!`0````````````(``P`!`````````#0```"08P```````#0`(``!
+M`"@`!P`$``$`````$`````````````"T4@``M%(```<`````$```````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`&`>!@^@#ZB)Y>EJ"0``B>P/J0^A!Q]ASP````!65XM\)!`/M'<\BT<P/0``
+M```/A)<````]`0```'4(@\8@Z8@````]`@```'4%@\8DZWP]`P```'4%@\8H
+MZW`]!0```'4%@\8LZV0]$@```'0E/10```!T)#T5````=",]%@```'0B/1<`
+M``!T08MW&&2M9HE'`&2M9HE'!&2M9HE'"&2M9HE'#&2MB4<09*V)1Q1DK8E'
+M&(/&!&2MB4<@9*V)1R1DK8E'*&2MB4<L9*V)1S!DK6:)1S1DK8E'.(EW/&:,
+M9T!?7LL`````````````P/__`````````(#_?P````````````#_________
+M__Y_0C$``$(Q``#8$@``LA(``$H$``!*!```E08``"L%``!*!```2@0``)4&
+M```K!0``908``&4&```*!P``4P8```H%```*!0``@P8``-\$``!*!```2@0`
+M`'X&```K!0``2@0``$H$``!^!@``*P4``&4&``!E!@``"@<``%,&```*!0``
+M"@4``&P&``#?!```2@0``+,&``#Q!@``*P4``+,&``"S!@``(0<``*$&``#Q
+M!@``(0<``/$&``##!@``"@4``*$&``##!@``WP0``$H$``#;!@``LP8``"L%
+M``"S!@``(0<``+,&``"A!@``\08``/$&```A!P``PP8```H%``#;!@``H08`
+M`-\$``"^Z````,9%Q/_&1<8"C7V\'@X?%@>Y`@```/.EB4VXBP9FB47('\,>
+M`>X6'Q8'C7VXN04```#SI1_#98`-!`````AE]@4`````"'4_@6W(`&```(%]
+MR/]_``!]+X"]</____\/A:0```!E@`T$````(("];_____\/A8\```!E@`T%
+M`````NF"````98`-!````"#H\B,``#P,=!R*1<3HH",``'4298`-!0````*^
+M\@```.E1____QT7(_G\``,=%N`````#'1;S_____QT7`_____X"]=/___P5\
+M,("]=/___PA_)[(#92(5`0```(#Z`G\9=!#'1;P`````QT7``/___^L'@66\
+M`/C__\9%Q@##9?8%`````!!U(&6`#00````0@47(`&```(-]R``/CR?___^!
+M;<@`8```O[C___^X`0```.B30@``Z"`C``"P_[^X____Z"HB``!F@[UP____
+M`'0D98`-!````#"`O6______=1-E@`T%`````O9%PX!T!<9%Q@##,<")1<B_
+MO/___^A^3```QD7&!G4$QD7&`<.#?#T0`'4LQT0]$`$```#V1#T+@'4=#[U,
+M/0AT%XM$/02#Z1_WV0^E1#T(TV0]!"E,/1##BT0]!`^]R(/I'_?9T^")1#T(
+MQT0]!`````"#P2#KW'0=Z%4C``!E]@4``````0^$&@$``.CO_?__Z9H```!E
+M@"4%````_8I%C@I%H@^%!`$```^VG73___^`ZP5FP>,"+O^3$`$``+^X____
+MZ"<B``"P`.@V(0``O[C____H:D$``(M%R#W^?P``#X^W````@_@`#XRV````
+MZ)?^__\AP'44O[S____HDTL```^%G0```,9%Q@&`O7#_____=1EE@`T$````
+M(("];_____]U"&6`#04````"O[C___^^?/___^DO`0``98`-!`````)E]@4`
+M`````G15OX#____HR?[__[^4____Z+_^___I0/___V6`#00````"9?8%````
+M``)T*K^`____Z)[^___I'____V6`#00````"9?8%``````)T">N\Z!;]___K
+MBL/HYOW__^N"J!!T)F6`#00````!9?8%``````%TXK^`____Z"H8``"^?/__
+M_^F6````@'V.`G0,@'VB`@^%D````.L,]D6+0'0,@'VB`G48]D6?0'4298`-
+M!`````%E]@4``````728OGS___^`?8X"=`>_E/___^M)@'VB`G0'OX#____K
+M/(I%C(IEH%"`98M_@&6??\9%C`#&1:``QH5T____!E;H42L``%Y8B$6,OX#_
+M__^`?<0`=`B(9:"_E/___X!,/0O`Z)$4``#I%2(``(I=HHI]CO;'!'0"MP/V
+MPP1T`K,#@>,#`P``P.<"`/LP_\'C`KC[0````H5T____]N0!PR[_HR`!``##
+M98`-!`````)E]@4``````G3MOH#____K+F6`#00````"9?8%``````)TU/95
+MH.L298`-!`````)E]@4``````G2]OI3____HJ/O__^MD98`-!`````)E]@4`
+M`````G2?OOP```#H</O__\9%Q@'K,V6`#00````"9?8%``````(/A'G____K
+M%F6`#00````$9?8%``````0/A&'____HV/O__\9%Q`"*98PZ9:!T`_95Q.G&
+M_?__BF6@@+UT____!G4"]M0Z98P/A$3___]E@`T$`````67V!0`````!#X0;
+M____Z.3Z___IC_W__P```&(.``"?#@``O0X``%(/``"3#@``)!```/$.``!'
+M$```EPX``*<.```5#P``YP\``)L.``"E#@``+@\``!`0```?#0``+0T``#8-
+M``!"#0``(PT``"@-```Z#0``,0T``/X-```"#@``!@X```H.```.#@``%0X`
+M`"$.```E#@``*0X``#$.```Y#@``00X``$D.``!*#@``4@X``%H.``!]&@``
+M0"H``!$?``!R,@``.R@``!<$```7!```%P0``!<$``"!*0``%AT``%,=```[
+M*```]AX``&$I``!7'@``$SH``!,Z``#;/P``*$H``!,Z``#\%0``X1\``%P4
+M``"U(P``N1T``#LH``"V*```ERD``-`I``"O*0``]!,``/03``#T$P``]!,`
+M`/03``#T$P``]!,``)<H``"3*```I2D``'(R``#I'0``(DP``,=-``#$3@``
+MX1\``'(R```%!P,P!C$(,@"$`3.;B9R=`!F,,P(-A(0I*H2$'R`A(B,D)802
+M$!,4#RXF)Q81%2T7&"LL`(0!,P``,S.,C*B.C(2$A`"$`3.+A(J>&AD!,R\T
+MA(0:&3,SGH2$A```!P<%`04!!P<'!P<'!P<'``4!!0(%`T1$``!`0```#`P,
+M#`P,#`!$:$>81V0``&1H1$=$E$1$`P<%!0<%!P4`!P$!```!`04'`P,'!0<%
+M`0<```,#```!``<'!0$%`0<'!P<'!P<'`@<%!0@$!04%!P("!04(!('LF```
+M`&:,T&:.V&:.P&8NBQ48````9H[J#P+0]\(``$``=1"!Y/__``"!Y?__``"S
+M`>L"LP"(70+W13@```(`=1#&10,!9HE%^HU%/(E%'.LRQD4#`(M%/(E%'&:+
+M14!FB47Z9HM%1&:)10AFBT5(9HE%#&:+14QFB44$9HM%4&:)10#\N20```"-
+MO6C___\QP/.K_+('B-%FNP("@'T#`74@Q74PQD7X`<9%^0$/`D4TJ0``0`!U
+M',9%^`#&1?D`ZQ(/MW4TP>8$`W4PQD7X`,9%^0!FBP9&)(=Y^(#$0-#0T,!F
+MO@`X9B'&9L'N"V:_'@!F(<=FT><.'P^_]@^__R[_ET0'``"`Y`=FB85T____
+M9HF5=O___V:)C7G___]FB;5\____9HF]?O___XB]>/___XB=>____X!]`P%U
+M$L5U,(FU;O___V:,G7+____K&XMU,(FU;O___P^W331FB8UR____P>$$`<X6
+M'V8QR3';9HM5#&:+!D8@P'A`/&=U!H!U^0'K[CQF=0:`=?@!Z^1F26:+500\
+M9'3:9HM5`#QE=-)FBU4(/"9TRF:+530\+G3"9HM5^CPV=+KKM$:(X_9%^0$/
+MA0D"```/MP909HM%#&:.V%B`^\`/@X@```#0XW(1>`R`XPZ`^PQT$V8QP$Y.
+M9IB#XP[1XR[_DX0'``!&1H!]`P%U)V:)E6S___^)A6C____VA73___^`=4EE
+M9F6)%1@```!EHQ0```#K.`^WTL'B!`'09HS29HF5;/___XF%:/____:%=/__
+M_X!U%V5FHQ0```")PL'J$,'B#&5EB148````@'T#`74%B77\ZPP/MU4TP>($
+M*=:)=?R^=O___[^`____QT6H`````,=%K`````#'1;``````QT6T`````.@T
+M#0``9E"^>?___[^4____Z",-``!F6V8)V(J==/___]#3<Q6*C73___^`^9MW
+M<8#YCG1L@/F*=&=E98H-`````/;1@.$_92(-!````'0$S1#KYO:%=/___X!U
+M1(!]`P%U&5#$A6[___]EHPP```!E9F6,!1````!8ZR50#[>%<O___\'@!`.%
+M;O___V5FHPP```#!Z!#!X`QEHQ````!8#[_;T<-F"<`N_Y/D!P``966*!0``
+M``#VT"1_92(%!````'0@L`"*C73____VP8!T!8#YFW<89F6!#00```"`@+`"
+MZPIF98$E!````']_BTW\B4TP(D4Y=`+-$.GO\O__9@-%(&8#113#9@-%$,-F
+M`T409@-%(,-F`T449@-%&&?C!\-F`T40Z_)FBU7ZPS'_@/S`<PN`Y`>`_`1U
+M`XH^1HL&'@^A4&:+10QFCMA8@/O`#X-K_O__@\8$T.-R&'@0@.,.1X#["@^$
+M\/W__S'`3H/N`P^^P(#C#X#["'01@^,.T>,N_Y.D!P``Z<[]__^(^R'_=!"`
+MYP>`_P5U"&2+!H/&!.L39HG?@^,'P>,"+O^3I`<``&:)^XC?@.<X@/\@#X27
+M_?__B-G`P0*`X0/0ZX/C'"[_D\0'``#I?OW__P-%+,,#12C#`T4DPP-%(,,#
+M11QGXPC#`T489^,!PV:+5?K#`T44PP-%$,.+?2S3YP'XPXM]*-/G`?C#BWTD
+MT^<!^,.+?2#3YP'XP\.+?1C3YP'XPXM]%-/G`?C#BWT0T^<!^,.Q`+4`BH:D
+M"```9HG79KH%`6:)UCPQ=`T\,G0-/#!U!+`#MP'#L`;K`K`(AM]FA\K#L0/K
+MS;$!Z\FQ`NO%9KD%!.O!LP&*AJ0(``!FB==FN@4!9KD%!&:)SNNYBH:L"```
+M9M'F#[_V9HN6``D``&:^``!FB<\\`'0,/#-T#3P!=`UFB?[#9KX%`\.W`;`!
+MPXJ&V`@``(J62`D``(JV4`D``&92BI8X"0``BK9`"0``9E[KOXJ&Z`@``&;1
+MY@^_]F:+EE@)``!FO@$`ZZ:*AM@(``"*EG`)``"*ME`)``!F4HJ6:`D``(JV
+M0`D``&9>ZX+VQ"!T3F:^`!]F(<9FP>X(#[_VBH88"0``T,"Y!````,#``F:_
+M!@!F(<</O_]F_[<0"0``XNJ*AK@(```\$'0(/!%T!#P4=0*W`69?9EYF669:
+MPV:)SXJ&M`@``#P`=!`\&705/#-T(#P!="!FB?[#9KH%!&:^!0/#9KH%`6:Y
+M!01FB<YFB=?#L`&W`6:Z!0%FO@4$PXJ&\`@``#PT=02W`;`O/"]U#V:Y!01F
+MB==FB=9FN@4!PSP:=:*W`.N>BH;X"```/!IU`K,!/)YUZ+4$Z^2`_"EU%;,!
+MMP&P+V:Y!01FB==FB=9FN@4!P["$9HG.9HG/PV:^``=F(<9FP>X(#[_VBH;@
+M"```Z^-FN`$`PP``'"0Y1!PD/$2^O+JY`0("`@$"`@._N/___^CF/P``OX#_
+M__^Q`>AA-0``Z/T5``"`^@-T!HI-@XA-N@^VVK]T$```+@^V##N(C6C___^-
+M=80V_W8$]D4"`70%#[?4ZP*)XDEU`4$V_S:#[@3B^(G(OW`0```NB@P[B(UN
+M____4.+]B=.)QXJ-:/___U$VBQ,[59QU"[C_____-HM3_.L6-HM#_/=UG(E%
+ML(E5K.L2BT6P2(M5K(E%L`-5G'(6B56LBT6P]V68.U6L<@AWX38[0_AWVS'`
+MB46TBH5N____B<'!X`+WV(G&BT0UH/=EL#8I!#-S`4*+1;0V*00S<P%"B56T
+M@\8$XN`V*10S<R3_3;"*C6[___^)R,'@`O?8B<;XBT0UH#81!#.#Q@3B\S81
+M##.+1;")1#W`64ET"X/K!(/O!.E$____B<B)QHJ-;O___]#A9C8+1#/^@^X"
+MXO4(Q`AENHG.BHUN____-HM$,_R)1#6(@^X$XO**C6C___\"C6[___^`^0)U
+M`4'!X0(!S,-H9!```.L%:&@0``"_N/___^A=/@``OY3___^Q`>C8,P``Z'04
+M```/MMI?+HH$.XB%;O___RX/MH-L$```B<>+18"+782+58@/K-@"#ZS3`L'J
+M`NL-T>#1T]'2<A"`3#T"("M%E!M=F!M5G.L%Z#<```#H/````/Z-;O___W76
+M(=)X!X!,/0(@ZP7H&@```(E%@(E=A(E5B`G8"=`/I,(09@G0",2(9;K#`T64
+M$UV8$U6<P]%EN-%5O-%5P,.+19`K1:0%_S\``(E%R(I%C#)%H(A%Q.BJ_?__
+MO[C____IZCX``(M%D`-%I"W^/P``B47(BD6,,D6@B$7$Z`H```"_N/___^G$
+M/@``'K^L____%A^-7#T`Z%D]``"_N/___^A1/0``N0@```"_E/___^@//0``
+M=00!SP'+OH#___^+1#4$"T0U`'4$`<X!RU>+?#T`,<F+1#4`]^<!`Q'1@_Z`
+M=`6)2P3K)HM$-03WYP'(@](`,<D!0P01T8M$-0CWYP'(@](``4,(@](`B5,,
+M7X/#!(/'!(/_H'6SOZS____HNSP``'0$@$VZ`1_#````````````@/\_`$#^
+MBAO-2WB:U`!``,"[\!=<*3NJN/\_`,`TPF@AHMH/R0!``*"8]\_[A)H@FOT_
+M`."K><_1]Q=RL?X_````````````````T.NX!@```/;C!2P2``")QL=%N```
+M``!F+HL&9HE%NBZ+1@*)1;PNBT8&B47`+@^W1@J)1<@QP(E%Q+(#O[C____H
+M;!$``+^X____Z*`Q``!E@"4%````_3'`BT6HG[^X____Z4,&``!T%.@0$P``
+M9?8%``````%T/>DH!@``98`E!0```/V*18X\`'1@/`9T0#P2=2*_@/___^@%
+M"0``98`-!`````%E]@4``````70%Z?`%``##/`)T!>GF!0``]D6+0'0%Z=L%
+M``"`38M`Z\YE@`T$`````F7V!0`````"=--FQT60`0#&18X`N#Y````Y19!]
+M6[^`____5^@(,0``7[(#L`#HIA```("]</____]U&66`#00````@@+UO____
+M_W4(98`-!0````(QP+^$____Z`D[``!T#[^`____Z*@\``#I6P4``(E%D,9%
+MC@'I3P4``+^X____Z!,[``"_E/___^@+.P``@>'_````^6I!G.L749RQ`>C3
+M.P``G9P0R0A-N[$"Z,X[``"*18LDP(A%EK$"Z,P[``"PP(IENYUR"L'@$.A,
+M````ZQCVU,'@$`%%E(M%O/?0$468BT7`]]`119Q9XJW0V0A-NF:+1;K^Q,'@
+M$.@<````OYC___\QP.A:.@``"D67=`2`3;I`L0CI6CL``+ZX____OY3____I
+MO@D``'00Z'`1``!E]@4``````751PV6`)04```#]BD6./`!U"(!]C`!U)>M/
+M/`9U"(!]C`!U&>LR/`%T*3P2=`\\`G4%Z7+^__^`?8P`=!;HZQ```'2^O[C_
+M___H/P<``.F+````Z>/^___HPA```'2COX#____H4.W__X%MD/\_``#W19`!
+M````=`7_39#K#K$!,,"_@/___^A8+P``BT60T?@%_S\``(E%R.BB_O__,<")
+M1<2_N/___^C8#P``Z.D.``"_N/___^@=+P``@+UP_____W4998`-!````""`
+MO6______=0AE@`T%`````K^X____Z:P#````Q)UH____,<")1#T$B$0]"":+
+M`XE$/0G!^!>(9#T,)?\```#'1:@`````=42*1#T+9@M$/0EU"L9$/0X!B40]
+M$,/&1#T.!L9%JO]E]@4``````G4!P\=$/1"!/P``#[U,/0B#Z1_WV=-D/0@I
+M3#T0PSS_=3+'1#T0_W\``/=$/0C___]_QD0]#@IT&O9$/0M`=0[&1:C_9?8%
+M``````%T!<9$/0X"P\9$/0X`!8`_``")1#T0@$P]"X##'L6=:/___\9$/00`
+MBP.)1#T%BT,$'XE$/0G!^!1FF8A4/0PE_P<``,=%J`````!U:(M$/00+1#T(
+M=07I/?___\9$/0X&QD6J_V7V!0`````"=0'#QT0]$`0\```/O4P]"'07BT0]
+M!(/I'_?9#Z5$/0C39#T$*4P]$,.+1#T$#[W(@^D?]]G3X(E$/0C'1#T$````
+M`(/!(.O<9CW_!W4[QT0]$/]_``"!9#T(____#XM$/0@+1#T$QD0]#@IT.?9$
+M/0L(=0[&1:C_9?8%``````%T*<9$/0X"ZPX%`#P``(E$/1#&1#T.`(M$/00/
+MI$0]"`/!9#T$`X!,/0N`PQ[%M6C___\6!X/'!%>-?#T`N0(```#SI6:+!E\?
+M9IF(5#T()?]_``")1#T,QT6H`````'0O]D0]!X!U!+(2ZPAF/?]_=`FR`(A4
+M/0HQP,.R"HM$/00E____?PM$/0!TZ+("Z^2+1#T$"T0]`+(!=-BR!NO4<AD`
+M`(,9``":&0``L!D``*,9``#T%@``KA<``"@<```W'```BAP``*L8```H'```
+M*!P``+@9``"`?#4`!W0B,=N)7#T`BEPU`<'C`B[_HQ\9``"*7#4`P>,"+O^3
+M,QD``#'`P^@]#0``Z!0"``!T(8G>'@^H'^D8____Z"8-``!F0.OEZ!T-```"
+MA77____KV.CC`P``9D##'L6U:/___Q8'C7V6N04```#S9J4?9H%]BO__=0N_
+M@/___^BY`P``PXI%GV:8B&6,OX#____H=C8``+$24;$$Z%0W``"#99\/Z%8W
+M``"^@/___^@XZ/__L0+H,3<``(M%N&8QP`%%@(M%O!%%A(M%P!%%B#'`BD6?
+M9@%%@K``$46$$46(6>*UOX#____H"C8``'4(B460QD6.`</'19!.0```OX#_
+M___H?C<``,9%C@##OQH``$P;``"S&@``OQH``%,;``!T$.CO#```9?8%````
+M``%U`<.?=0AE@"4%````_;^`____OGS___\/MEPU`<'C`B[_HVD:``#H#0P`
+M`&9`Z9\```">#X6!````Z,\```!T&NBR#```9?8%``````$/A+D```#HLP(`
+M`.M@BT6H"<!T60C`=!UE@`T$`````67V!0`````!#X21````@$P]"T#K.`CD
+M=!1E@`T$````!&7V!0`````$='3K(&6`#00````"9?8%``````)T8("]=O__
+M_P%W!<9$/0X`Z$L-``#H=`L``.L+Z&T+```"A77___^#X`>)P8I$/0[H^0P`
+M`(UT/02_'`````'/P>$"`<^Y`@````^H!QX6'_.EBB9F)0"`9@M&!!]E9F6)
+M!\/H)@L``&9()`?H*PL``#P#PXUU@(U]E.CN#@``@'V.`'46QT6D_S\``(M%
+MD"W_/P``OX#____K;H!]C@9U),9%JO]E]@4``````G0@OY3____HU.?__XM%
+MI,=%I/\_``#KRH!]C@%T!<9%C`##QD6I_V7V!0`````$=/''19#_?P``QD6+
+M@,=%C/\`"@##Q)UH____9B:+`P^_P.L)Q)UH____)HL#B<(QP(E$/0")1#T$
+M"=!U$HE$/0B(1#T,QD0]#@&)1#T0PYF(5#T,>0+WV`^]R(/I'_?9T^")1#T(
+MN!Y````IR(E$/1#&1#T.`,,>Q;5H____%@=7C7P]!+D"````\Z5?'XM$/0B9
+MB%0]#$)U%/=4/02#1#T$`?=4/0B#5#T(`.L0"T0]!'4*B40]$,9$/0X!P\=$
+M/1`^0```#[U,/0AT%XM$/02#Z1_WV0^E1#T(TV0]!"E,/1##BT0]!`^]R(/I
+M'_?9T^")1#T(QT0]!`````"#P2#KW.C&#```Z`4```#I/`P``+$%Z)D)```>
+M#Z@?]N%FN2@`9BG!OAP```!6F`'&`<8/M\GS9J5FB<%>\V:E'\/H7@L``+$%
+MZ&8)```>]N&Y*````&8IP;\<````5Y@!QP''Q;5H____@\8.@'WX`74#@\8.
+M\V:E9HG!7_-FI1_I50L``,,QP(E$/03'1#T(````P,9$/0S_QT0]$/]_``#&
+M1#T.`L-T#^BS"0``9?8%``````%T[F6#)04```#]Z,/\__\QP)^_E/___[Y^
+M____Z;O\__]T$F6`#04```!!98`E!0```/GK2V6`)04```"XBD6./!)T/#P"
+M="`\"G04/`9U"F6`#04```!$ZR;V18N`=`AE@`T%````!-#(<PAE@`T%````
+M0-#(<PAE@`T%`````?9%C`%T"&6`#04````"PW0AZ!4)``!E]@4``````71&
+MOY3____H)O___PS_G^E@____Z!O]__]T!>E1____98`E!0```/W'1:@`````
+MBD6./!)U'V7V!0`````!=0EE@`T$`````<._@/___^C?_O__ZQ@\`G4M]D6+
+M0'429?8%``````%TUX!-BT#&1:C_C76`C7V4Z,(+``#HL_O__^GK_O__Z+K\
+M___IU/[__W00Z'8(``!E]@4``````74%P\9%C`#I@?O__W00Z%L(``!E]@4`
+M`````74$P_95C.EG^___`%"Q`>A[,0``L0'H:S$``+Z4____O[C___]FQT0U
+M````N0,```"X`````!M$-0")1#T`1D9&1D='1T?BZ>L44>CK,0``OI3____V
+MA6C___\!=`6^N/___[^`____Z"8```#0E6C___]9XM3VA6C___\!=0^^E/__
+M_[^`____Z`4```#IJ#$``(M$-0!F,<`!1#T`BT0U!!%$/02+1#4($40]",,!
+M[P'N'A8?%@>Y`P```/.E'\.?98`E!0```/EFQX5H____``">=`KH>`<``.GF
+M`0``BD6."D6B#X7.`0``BT60*T6DOX#___]\8X/X/WX.98`-!0````2#R""#
+MX#\I19!`Z/?^__\QP+^$____Z/8O``!U&67V!04````$#X0:`0``B(5H____
+MZ0\!``"_@/___^A\,0``9?8%!0````1T#,:%:/___P#IN````)^`O73___\N
+M#X6J````GG4'L0'HO#```/]-I/]UC,9%H`#&18P`QH5T____!HM%D#M%I+Z`
+M____?@6^E/___[_@____Z`K____H>!```+^X____Z'\O``"/18R_@/___W44
+M]H5H____`71-_H5H____]E6,ZT*^X/___X!]Q`!T#.C-_O__OX#____K*XM%
+MD#M%I'0*OY3____HM/[___Z%:/____]%I(I%C(A%H.@3$```O[C___^#?#T0
+M`7UAB?[H!>'__V7_-0````!E@`T!`````\:%</___P#HU>'__V6/!0````"_
+MN/___^LQB460QD6.`8"]=/___RYU',9%C`!E]@4!````!'0.9?8%`0````AU
+M!,9%C/^_@/___[Y\____Z/[X__]E@"4%````O(J%:/___\#@!G,(98`-!0``
+M``'0X',(98`-!0```$#0X',(98`-!0````+#J!!T)F6`#00````!9?8%````
+M``%TZ;^`____Z)[[__^^?/___^D*Y/__BD6BBF6.@/P"=`8\`G4IZPKV18M`
+M=`H\`G48]D6?0'4298`-!`````%E]@4``````72BZ7+C__^`O73___\8#X2M
+M````@/P*=)`\`72,@/P&=6-E@`T$`````F7V!0`````"#X1L____OX#___\\
+M"G4]]D6+@'00QT60`0```,9%C@#I;O___V7V!0`````0#X5@____Z"7A__^!
+M19``8```98`-!````!#I1____U#H"^'__U@\!G4B98`-!`````)E]@4`````
+M`@^$!?___[^4____4.CEX/__6(#\`0^$KO[__SP*#X2F_O__Z1;]__^`_`IU
+M:(!]C`!U+CP!#X35_O__/`9U$F6`#00````"9?8%``````)T6XI%H(A%C+^`
+M____Z?\````\"@^$I_[__SP&=1)E@`T$`````F7V!0`````"="V_E/___^@1
+M+0``B46DQD6B`>G+````@/P&=1-E@`T$`````F7V!0`````"=0'#/`8/A:8`
+M``!E@`T$`````F7V!0`````"=.6`_`!U#+^4____Z"#@___K+V7V!0`````0
+M=7GIE````'0*Z+<#``#I)?[__V6`)04```#]BD6."D6B#X4%_O__9?\U````
+M`&6`#0$````,Z(L+``!ECP4`````=`B`?8P`=`SK&(M%B#T]X```?@>X/>``
+M`.L,/0(@__]]!;@"(/__`46D@7VD_G\``'\5@WVD`7P@OY3___^^?/___^EL
+M]O__OI3____H!=[__^@3WO__ZRR^E/___^CTW?__9?\U`````&6`#0$````#
+MQH5P____`.C$WO__98\%`````+^X____Z[*'3#T&(<EY`O;6@>'___]_"TP]
+M`F8+3#T`=`+VTC#D]D0]"@%T$?;4QT0]`@````!FQT0]````N0(!``##ADP]
+M""#)>0+VUH#A?PM,/00+3#T`=`+VTC#D]D0]"0%T`O;4QT0]!`````#'1#T`
+M`````+D#`0``PX=,/00AR7D"]M:!X?___W\+3#T`=`+VTC#D]D0]"`%T`O;4
+MQT0]``````"Y!`$``,.+3#T$]L4$=`+VUH'A_P,```M,/0!T`O;2,.3V1#T%
+M"'0"]M3'1#T``````&:!9#T$`/BY!P@``,.'3#T`(<EY`O;6@>'___]_=`+V
+MTC#D]D0]!`%T`O;4N0@!``##N20``/,D```D)0``724``'PD```*)@```B8`
+M```F```Q)@``,/8/O_+!Y@)F,=(QR2[_EH(E``!F(=)U&SS_B-!U!XB%<?__
+M_\-FB95P____B(5O____PSS_=0B(A7'____K"6;'A7#_____`%#HM0````^V
+MV%@N_Z.6)0``]M<X?#T,=3/K)XC7".(\_W4;BIUP____9H'[_P!U#CJE;___
+M_W4&9D)T!NL.9D)T"K``B(5O____ZRC&A6______B.HP[;L,````*<L!WS#`
+M`%0]`$=)$$0]`$?B^1C`@^\,PXC$Z#\````\!'4'(.1T"S#`PSP(=?D@Y'3U
+M#/_#Z"0````\!'3T/`AT\.OCL@-E(A4!````PV6`)0$```#\90@%`0```,-E
+M98H%`0```"0,PV6`)0$```#S90@%`0```,-E98H%!0```"0XP.@#PP^VP(G!
+MT>&)R\'C`@'+@\,<96:A"````&;3Z"0#/`)U+&5F98M#"&8E_W]U`[`&PV5E
+MBT,$J0```(!U`[`2PR7___]_90L#L`IT`K`"PV7V!0`````0P^B*````9?8%
+M``````+#Z',```!E]@4``````<-E]@4`````",-E]@4!````$,-E]@4$````
+M(,-E]@4$`````<-E]@4$`````L-E@`T$````066`)04```#]PV6`#00```!!
+M98`-!0````+#98`-!````"##98`-!````!##98`-!`````C#98`-!`````'#
+M98`-!`````+#98`-!`````1E]@4`````!,-E@`T%`````<-E@`T%````0,-E
+M@`T%`````L-E@`T%````!,-E@"4%````_L-E@"4%````O\-E@"4%````_<-E
+M@"4%````N,-E@"4%````^\-E@"4$````W\/H"____W4'Z"C___]U>HJ%>/__
+M_^@&````BH5[____/`%T.30`=33H;/[__P*%=?___R0'B,&P`]#A9F73#0@`
+M``!E@"4(````_"0#90@%"````&9ETP4(````P^@W_O__Z,[___^Q".L"L3AE
+M98H%!0```"0X93`%!0````#()#AE"`4%````PQX/J`?%M6C___^_`````+D'
+M````@'WX`74-\Z4?98`-`````$#K#V:E1T?B^A]E@`T`````0+D(````,=NX
+M"@```/?COAP````!QK@#````92,%"````(/X`W1"969EBT8(9B7_?W099?9&
+M!X!U!+("ZQQF/?]_=`2R`.L2L@+K#F5EBT8$90L&L@%T`K("98`E"````/QE
+M"!4(````9F7!#0@````"0^*3PV:X?P-E9J,`````9KC__V5FHP@```!F0&5F
+MHP0```##Q)UH____9B:+`V8-0`!E9J,`````P^A%````98`-`````'_#967&
+M!00`````PXJ%>O___SP$96:A!````'0+Q)UH____9B:)`\-FB44LPV5FH0``
+M``!F)7\?9@U`$.O?'@^H'V9E@24`````?Q]F98$-`````$`0O@````#$O6C_
+M__^Y!P```(!]^`%U!/.E'\-FI49&XOH?PP!++```SRT```LO``#$+P``B3``
+M`+(J```++P``"R\``.8J``!T#^@L_?__9?8%``````%T8&6`)04```#]@+U]
+M____!'4*Z#/P___IP?W__P^VG7S____!XP*#^PA](H!]CA)U'&6`#00````!
+M9?8%``````%T'K^`____Z/OR__\N_Z,<*@``'A8?%@>Y!0```/.E'\/$O6C_
+M__\>%A^-=82Y`@```/.E'XIEC&8E`(!F"T609B:)!^E3_?__````````0'8Z
+M:PO>9?\U`````&6`#0$````#@'V.`74%Z1\!``"!?9#_?P``=3!E@`T$````
+M`67V!0`````!=07I(P$``,=%@@````#'188```"`9L=%BO__Z>\```"`?8X&
+M=0O'19`!````QD6.`+@^0```.460?;6_@/___U?HGQH``%^R`[``Z#WZ__\Q
+MP+^$____Z,(D``!U"8E%D,9%C@'K?8M4/02!^K.VX`T/AWG___^+1#T`<@L]
+M``!DIP^#:/___\=$/00`````QT0]``````"#[P*[`,J:._?S4+D$````NV0`
+M``")T#'2]_.2U`K`Y`0(X(A$/0!'XNM8"<"(5#T`=!E2,=*Y"@```/?QDEF(
+MQ(C(:@"Y!0```.O2@+UP_____W4998`-!````""`O6______=0AE@`T%````
+M`HIEC(#D@(AEBV7$/10````>%A^-=8*Y!0```/-FI1_HZOO__V6/!0````##
+M:"TH``#$O6C___^^@3\``+(`BD6./`!T1#P&=#8\`G4<]D6+0'4698`-!```
+M``%E]@4``````709@$V+0(M-B8'A__]_@`^V19#!X!<)R":)!\._@/___^@<
+MU___OWY```#H0@```,2]:/___W0M>"2+18DE____@*G___\`=!$E__]_@`^V
+M39"`P8#!X1<)R":)!\.X?___?^L%N'\``(`*18S!R`CKZ%=64K``OX#____H
+MH_C__^C<&```6EY?.760?%$/A(@````Y?9`/CHD```!E@`T$````"&7V!0``
+M```(=0-86,-E@`T$````(&5EB@4!````)`RT"#C$>!2*18SH$/G__YQX"&6`
+M#04````"G<-E]@4`````$'4*98`-!````!#KO+^`____B?!74NA[&```6E^P
+M_^@:^/__9H.]</___P!T"&6`#00````P]D6+@'4$9O]-D&:#O7#___\`=!EE
+M@`T$````(("];_____]U"&6`#04````",<!`PV@M*```O@$\``"R`HI%CCP`
+M=$,\!G0U/`%U"&;'19``/.M2/`)U'?9%BT!U%V6`#00````!9?8%``````%U
+M`<.`38M`9L=%D/]#ZRF_@/___^B?U?__O_Y#``#HQ?[__W1]>&B*185FF+^&
+M____Z/HA``!T.[$#Z&0B``#$O6C___\>%A^-=86Y`P```/-FI1]FBT609BT`
+M/&;!X`2`98L/"D6+@&6,@`IEC&8FB0?#,<#$O6C___\FB0=F)HE'!(IEC(#D
+M@&8FB4<&P[C_____Z-S___]FN.]_"F6,Z^?HS/___V8F@4\&\'_#N0Y````K
+M39!X18/Y$78%N1$```"_@/___S#`Z!07``"_@/___[($L`#HO?;__SP`=1UF
+M@7V*`(!R"'<3@'V,_W4-L``Z18QT!F;W78HPP,.`?8X`=`:`?8X&=3WHG___
+M_W4V9H.]</___P!T&66`#00````@@+UO_____W4(98`-!0````)FBT6*Q+UH
+M____9B:)!^G9^/__9C'`@'V.`73H98`-!`````%FN`"`9?8%``````%UTL.Y
+M'D```"M-D'A%@_DA=@6Y(0```+^`____,,#H6Q8``+^`____L@&P`.@$]O__
+M/`!U'8%]B````(!R"'<2@'V,_W4,L``Z18QT!?==B##`PX!]C@!T!H!]C@9U
+M.^B?____=31F@[UP____`'0998`-!````""`O6______=0AE@`T%`````HM%
+MB,2]:/___R:)!^DB^/__,<"`?8X!=.IE@`T$`````;@```"`9?8%``````%U
+MT\.Y/D```"M-D'A3@_E!=@6Y00```+^`____,,#HI!4``+^`____L@.P`.A-
+M]?__/`!U*X%]B````(!R#G<@@WV$`'4:@'V,_W44L``Z18QT#3'`]UV$&T6(
+MB46(,,##@'V.`'0&@'V.!G5"Z)'___]U.V:#O7#___\`=!EE@`T$````(("]
+M;_____]U"&6`#04````"BT6$BU6(Q+UH____)HD')HE7!.E6]___,<"9@'V.
+M`73E98`-!`````&Z````@&7V!0`````!=<[#BT6`9C'``T64B46XBT6$$T68
+MB46\BT6($T6<B47`L`#0T,.+18"!990``/__*T64B46XBT6$&T68B46\BT6(
+M&T6<B47`L`#0T,.^[T4``.L%OD\R``"+39`K3:1X*8/Y0W8%N4,```"P`+^4
+M____5O_67HM%D(E%R(!]C@%T,_9%BX!U+>L=]]F#^4-V!;E#````4;``OX#_
+M____UHM%I(E%R%F`?:(!=`BP`/9%GX!T`K#_@+UT____!G4#]E6@BF6,.F6@
+M=2CH,____[^X____Z!44``"*18R(1<3V1<.`=0R_N/___^AN'@``=5W#4(I%
+MC(A%Q.@G____O[C___\\`+@`````=!SW5#T`@T0]``'W5#T$$40]!/=4/0@1
+M1#T(]E7$Z#`>``!U&NB`]/__-`1F2&:8B&7$6#S_=19FQT7(``##6#S_=0J_
+MN/___^B4'P``P^AB'@``BT0]`"7___\?"<)T"(%,/0`````@@60]`````.##
+M=!5E@"4%````_66`#00```!!Z2@!``#'1:@`````98`E!0```/F`O73___\I
+M=17&1:``QD6B`;^4____Z+4=``")1:2*18X*1:)T=CP!='*H$`^%WP```(I%
+MCHIEHCP"=`>`_`)U+>L/]D6+0`^$Q````(#\`G4*]D6?0`^$M0```("]=/__
+M_R\/A,D```#IHP```(!]C@9U$<9%JO^#?9``=0?'19`!````@'VB!G41QD6J
+M_X-]I`!U!\=%I`$```#&A73___\&Z`+^__^_N/___^@)'0``#X2$````98`E
+M!0```+[V1<0!=`AE@`T%`````8-]J`!U!>F\]/__@'VH`'0;9?8%``````%T
+M!>FG]/__PX!]J@!U!>F;]/__98`-!`````)E]@4``````G3BZ83T__]E@`T$
+M`````<=%J/\```#K$(!]C@9T!H!]H@9U!,9%JO]E@`T%````!>L(98`E!0``
+M`/YE@`T%````0.N```"``````````````(```````````````````/4?F.S`
+MN_`77"D[JK@``````````````0```````````,``A&3>^3/S!+4```"-]!$%
+M7ZQ_B@```````````(``_________[\`H)^'UOLY&L"5`&#R5]QH7L+3I``@
+M_3RTWL_1`*X`@.:SF$C6MQ^S`,").>QWK)O6M0"`4TR1%BZT/+<`@/R+0GBW
+MA?*W`.!6NF/5:R-.N`#@,2:K4_@??+@`8/V@HA^Z*9.X`,!7&+[*>[&>N`"@
+M<$3^#15VI+@`8*H;F]*/6*>X`&"4Z9J^V,FHN`"`,W(E%X""J;@`P#3":"&B
+MV@_)`(!%>]H-*SAC[0!@%>L&9,FOV_H`P#)N>V'5U*W^`,`V3N]GN=VJ_P"`
+M0B6Q2]VMZO\`X+O5E-O=JOK_``!HN=3=K:K^_P#`2[G=W:JJ__\`H$O=W:VJ
+MZO__`*#;W=VJJOK__P#@W=VMJJK^__\`X-W=JJJJ____`.#=K:JJZO___P#@
+MW:JJJOK___\`X*VJJJK^____`,PY``"S.0``L#D``*<Y```6.0``I$$``*I!
+M``!!.@``-#P```D\```'.P``"3P``$`\```)/```\SL``#0\```T/```03H`
+M`!X\``#B.@``'CP``/,[``"S.@``03H``/<\``#`/```!SL``%L\```D.P``
+MWSP``%L\``"O/```)#L```,]``"9/```XCH```T]```-/0``LSH``$$Z```[
+M/0``.ST```<[``!9/0``.ST``"0[``!#/0``KSP``"0[```#/0``F3P``.(Z
+M```E/0``)3T``+,Z``!E_S4`````98$-```````#``!E@`T$````(,9%Q`!F
+MQX5L____``"+1:0K19")1:B#^`]^/X/X/W\%Z=````#H$-S__^@H#P``BT7(
+M@_@`#X\%`@``#XP#`@``O[S____H=!D```^%\P$``,9%Q@'IZ@$``.C-&0``
+MZ-$9``#H.OK__V;1I6S___^`?<,`=53H1AL``+^`____Z)<9``#H]OG__^A'
+M&P``ON@S``#H;AL``.@Q&P``@664````_^@+&P``9O^%;/___X!]PP!T$[D!
+M````Z&T9``"!990```#_ZP7H%!H``/]%J(-]J`]VC+D'````Z`,:``"!98``
+M``#@QT6H#P```.CA&0``Z`;9___HUQH``+D)````Z"X9``"!98```.#_Z+H:
+M``#H$AD``(%EE```X/^!9;@```#@Z)0:``#H3OG__^B1&@``Z'D:``#H;1H`
+M`+D>````Z.P8``#'18``````N1X```#HB1D``.@EV___O[C____HL1@``,9%
+MP\#H6QH``(%EE````."`??<`L`&Y!P```'4'L`"Y"````%"_[O___^A0&0``
+MZ`,:``#H7-C__X%EN````.!8T.BY!P```',%N08```#H9A@``.@2&@``9M&M
+M;/___W,9N`H```#W9:@%XC0``(G&Z"8:``#H\!D``&:#O6S___\`=!:Y`0``
+M`.@]&```@66```#@__]-J.N^@'V+`+D(````=`BY!P```/]-J.C'&```QT60
+M_C\``(M%J"E%D+^`____Z!49``#H1!D``(M%D(E%R,9%Q@!ECP4`````P\=$
+M/0``````QT0]!`````#'1#T(`````,=$/0P```$`QT0]$`````##QT0]````
+M``#'1#T$-<)H(<=$/0BBV@_)QT0]#`````#'1#T0_S\``,.*58R*=:#&18P`
+MQD6@`(CS@^,(BT6D.T60?S=\*XM%B#M%G'\M?"&+180[19A_(WP7O[C____H
+MG/____]-R`G;#X2S````ZSA3Z!<2``!;@\L$4U+H[_S__UI;"=MU(8M%R(/X
+M`']/?`:`?<8!=&=2Z*?)__]:98`-!````!#K>;^`____Z$W___\N_Z."-0``
+MQH5T____!>L*_T60QH5T____!E*-?92-=;CHWO#__^AW]___6F7_-0````!E
+M@0T```````,``%+HZPL``%IECP4`````9H.]</___P!T&66`#00````@@+UO
+M_____W4(98`-!0````*(5<3#=!?H6>W__V7V!0`````!=0'#Z/;'___K>&6`
+M)04```#]#[9=C@I=H@^%W@````^VG73___^`ZQ1T4(#[_'0\@7V0_S\```^/
+MQ0```'PF@'V,``^$N0```(%]B````(`/A:P```"#?80`#X6B````Z=0!``"[
+M"````.L/@'V,``^%C````+L$````+O^3DC4``+^X____OGS____I6\O__V6`
+M#00````"9?8%``````(/A%O___^_@/___^CQR/__OY3____HY\C__^E?____
+M98`-!`````)E]@4``````@^$+/___[^`____Z,+(___I.O___V6`#00````"
+M9?8%``````(/A`?____KM/;#$'0;98`-!`````%E]@4``````0^$ZO[__^GF
+M_O__@'V.`G0(@'VB`G4OZPSV18M`=`R`?:("=1SV19]`=19E@`T$`````67V
+M!0`````!#X2O_O__Z33*__^*?8X/MH5T____+!1T03S\="F!?9#_/P``?!D/
+MA,;^__^!?9#_?P``=8"`?8P`#X5V____N(````#K%(!]C`!T"8#_`0^%8/__
+M_[A`````BEVB]L<$=`*W`_;#!'0"LP.!XP,#``#`YP(`^S#_P>,"`<,N_Z.>
+M-0``98`-!`````)E]@4``````@^$&_[__X!]H`!T-[^X____Z-3\____1<CK
+M,F6`#00````"9?8%``````(/A/#]__^_N/___^BO_/__ZQ"`?:``=<F_N/__
+M_^AT_/__BE6,B%7$Z4G^__]E@`T$````!&7V!0`````$#X2S_?__QT6(````
+M@,=%C```"@#'19#_?P``OX#___^*5:#VTHA4/0SI$/[__V6`#00````"9?8%
+M``````(/A'7]__^_@/___XI5H(A4/0SIZ?W__X%]D/\_``!_.GPU@7V(````
+M@'<O@WV$`'4IZ47^__]E@`T$````!&7V!0`````$#X0O_?__ZPF!?9#_/P``
+M?0/V5:"_E/___^F<_?__98`-!`````)E]@4``````@^$`?W__^O;98`-!```
+M``)E]@4``````@^$Z?S__XI5C#!5H.O`98`-!`````)E]@4``````@^$R_S_
+M_XI5H#!5C+^`____Z4#]__];_W0U`/]T-03_=#4(_W0U#/]T-1#_XUN/1#40
+MCT0U#(]$-0B/1#4$CT0U`/_CQT0U``````#'1#4$`````,=$-0@```"`QT0U
+M#`````#'1#40_S\``,-FQX5L____``"X_S\``"M%D(/X/W]1B460@_@/=W[H
+MRA(``+@*````]V60!4(T``")QNBA%```9M&E;/___X!]PP!U$^A%%```@66`
+M``#@_V;_A6S_____19"#?9`/=S#H-A,``.N\QD6@`,=%I/\_``"^!C0``.AM
+M%```Z`T3``#H;-3__^B$!P``Z2X!``#'19`/````Z/L2``#HG!,``+$>Z$<2
+M``"#98``L1[HZA(``.B&U/__Z-$3``"!98````#@OOPS``#H$10``(M-D(/!
+M"N@$$@``@66X``#@_^B($P``Z`,2``#HF!,``.AG\O__BTV00>C@$0``@66X
+M``#@_^A^$P``O@8T``#HMA,``.A5$P``Z&H3``#H;!(``.B1T?__N0@```#H
+MK!$``(%EN```X/]FT:UL____<R3H2!,``.@\$P``BTV0Z),1``"!990``.#_
+M9H%-GH``Z-/Q__]F@[UL____`'01Z&<1``"!9;@``.#__TV0Z[BQ"(!]PP!T
+M!;$'_TV0Z/41``"X_S\``"M%D(E%R,=%Q`````#V1<.`=0JQ`>C6$0``_TW(
+MZ-42``#H[1(``,/V58SH.?[__XUUN(U]E.@2Z___OH#____H^_W__\9%C/_&
+MA73___\&OKC____HN/W__^B,\?__Z!0&``"-=;B-?93HWNK__[Z`____Z+#]
+M___HW=+__^CU!0``P^CW!@``=07IL]K__X%]D/\_``!_\GP:@7V(````@'?G
+M@WV$`'7A@'V,`'3;_TV0Z]9E@`T$````(&7_-0````!E@0T```````,``&6!
+M)0````#_\___@7V0_C\``'0(@'V,`'59ZQ6!?8@```"`=U6#?80`=4^`?8P`
+M=4+H9/W__XM-R(/Y`'X&QD7&`.L-Z,/"__]E@`T$````$("];_____]U"&6`
+M#04````"98\%`````+^X____Z0;:___HX?[__^N\@'V,`'5_OI3____HY_S_
+M_\:%=/___P;HAO#__^@.!0``C76XC7V`Z-CI___HKO[__XUUN(U]@.C(Z?__
+MOI3____HL?S__\:%=/___P7H4/#__^C8!```_T7(C76XC7V`Z)_I__^^E/__
+M_^B(_/__QH5T____!N@G\/__Z*\$``#I4O___[Z4____Z&C\___&A73___\%
+MZ`?P___HCP0``(UUN(U]@.A9Z?__Z'#\__^-=;B-?8#H2>G__[Z4____Z#+\
+M___&A73___\%Z-'O___H600``(UUN(U]@.@CZ?___TV0OI3____H"?S__\:%
+M=/___P;HJ.___^@P!```Z=/^___&1=H`ZP3&1=H!9?\U`````&6!#0``````
+M`P``O^+____H)1```(I%HHA%XHM%I(F%:/___XI%H(A%SL9%V`"`?=H`=2CH
+MOPX``+XD-```Z*`0``"`?<,`=5SI7`$``.CN#P``QD78_^F+`0``BT60B47(
+M@'V,`'7FZ.4/``"Y_S\``"M-D(/Y2'8%N4@```#H;0X``&:+39:!X?\?```)
+MRG0&9H%-E@`@@$V?@(%EE````.#K.^CX#@``Z)(/``"Y`0```.C9#@``O[K_
+M___HN@T``'0XQT7(_C\``+^X____Z%</``#H=P\``.BY#P``_[5H____Z-C-
+M__^/A6C___^!9;@```#@Z=0```#H]-C__[^"____Z'$-``!U%\9%C@&*1<XP
+M18R-=8"-?;CHS.?__^MO@67@````_^A`#P``BX5H____B46DBD7.B$6@Z-[/
+M___HT`(``(M%R#W^?P``?TB#^`!\2G\2O[S____H'0T``'4\QD7&`>L$QD7&
+M`&:#O7#___\`=!EE@`T$````(("];_____]U"&6`#04````"98\%`````,/H
+M!+___^OQZ-6____KZO]%D.B@#@``OA`T``#H&`\``+D'````Z,P-``#&1=C_
+MQT7(_S\``+^Z____Z*(,``!T"K^X____Z$8.``#HI@X``&;'A6S___\``+C_
+M/P``*T7(B46H@_@/#X>0````Z(L.``"Y!P````--J.C?#```Z,\,``#H'NW_
+M_X!]PP!T&8%EN```X/_&1<,`Z%<.``!FQX5L____`0!FT:5L____Z.4-``"+
+M3:CHH@P``(%-B```@`#HW^S__X!]PP!T%X%EN```X/_&1<,`Z!@.``!F_X5L
+M____N0$```#H$`T``/]%J(-]J`]VL.@`#0``98`-!````"#HCPT``.B>SO__
+MBTVH@_E(=@6Y2````.@K#```@66X````X.C)#0``Z)CL___HN`T``(M-J(/Y
+M2'8%N4@```#H%0P``(%E@````.#H80T``+X:-```Z-D-``#HF0T``.A9#0``
+MBTVH08/Y2'8%N4@```#HV0L``(%EE````/#H0NS__X%EN````.#H-0T``.A=
+M#0``_[5H____Z(/+__^/A6C___^!9;@```#@Z$<-``"^+C0``.B.#0``N0<`
+M``#H@@L``/]-J&;1K6S___]S(HMUJ$ZX"@```/?FB<:!QDPT``#H:@T``.@*
+M#0``Z*_K__]F@[UL____`'0*Z$,+``#_3:CKP;@'0```*T6HB47(@66X``#@
+M_[^X____Z-H*``!T"K^X____Z%T,``"`?=H`=3CH&];__^BR#```BT7(B46D
+MQH5T____!8I%V(A%H.B<Z___Z)P,``"*1<2(18R+1<B)19#I]/S__XI%V(A%
+MQ.OBQD6Z`;(#O[C___^P`.C)W___O[C___^T!*@!=0'#_T0]$+$!Z,(*```A
+MTG0%@$P]`@'#B<&'1#T0*<&#^4-^!;E#````,,#KVW0JZ%CA__]E@"4%````
+M^V7V!0`````!=0)8P[^`____OG[___]8G^EDU/__98`E!0```/OH3=7__W0$
+M,<#KW,=%J`````!E@"4%````_8I%CCP!=FT\!G(.=#^_@/___^@?U___ZPKV
+M18M`=<Z`38M`9?8%``````%U"F6`#00````!ZY2-=8"-?93H`.3__\9%J/]8
+MZ1S7__]E]@4``````G4-98`-!`````+I:/___\9%JO^_@/___^CQO/__@\@!
+MPW0?Z)7@__]E@"4%````^V7V!0`````!=0)8PUCIHM/__V6`)04```#YBD6.
+M/`%^:SP&?"IT1H"]=/___Q)U$SP2=`^`?8P`=-+'19#_/P``Z\F_@/___^AE
+MUO__ZPKV18M`=;>`38M`98`-!`````%E]@4``````72?ZY]E@`T$`````F7V
+M!0`````"=(N_@/___^A5O/__@\@!PS'`BH5T____BF6,B46LQD6,`&;'A6C_
+M__\``(M%D"W^/P``?%6#^#]^"F6`#04````$6,/'19@UPF@AQT6<HMH/R<=%
+MH`````#'1:3^/P``*4600.A@U___BT6$"T6(=0^)18")19#'18X!````ZQ*_
+M@/___^CU"0``98`-!````"#VA6C___\$=`1F]U6M]H5H____`G0&]E6O]E6N
+M]H5H____`74!P_95KX!]C@%U)X!]K!-U(<9%BX#&18X`QT60_S\``+Z4____
+MZ%3U__^#Q`3I(@,``&6`#00````@QT64`````,=%F#7":"''19RBV@_)QT6@
+M`````,=%I/X_``#&18S_QH5T____!>B\Z/__9?\U`````&6!)0````#_\___
+MZ#+]__]ECP4`````C76XC7V`Z/7A___#9L>%;/___P``B460@_@0?UC_39#H
+MY`<``+@*````]V60!>(T``")QNB["0``9M&E;/___X!]PP!U$^A?"0``@66`
+M``#@_V;_A6S_____19"#?9`/=P?H4`@``.N\Z$4(``#'18``````Z-\(``#H
+MV\G__XM-D-'A@\$(Z&T'``"!9;@```#_Z`L)``"^0C0``.A#"0``Z-L(``#H
+M5`<``.C8"```L0GH4P<``.C8"```Z)+G___H,`<``.C0"```_TV09M&M;/__
+M_W,VZ*P(``#HC0@``.AMY___Z+`(``"+39#1X>@,!P``@664``#@_^AUY___
+MZ(X(``"!9>````#_9H.];/___P!T&+$!O^S____H[`8``(%E[```X/__39#K
+MG[$(@'WW`'0%L0?_39"_[O___^AW!P``Z"H(``"X_S\``"M%D(E%D+^`____
+MZ-T'``#H'`@``.@_!P``QT6D_S\``,=%H`````"_E/___^B[!P``P^CG^___
+M=0^^E/___^A>\___Z8S3___H,/W__X!]C@%U+X!]K_]UX,=%@`````#'180`
+M````QT6(````@,=%C```"@#'19#_?P``QD6I_^NWN/\_```K19"#^#]^?#W_
+M/P``?$"*1:V(18QE@`T$````$&7V!0`````0=0F!19``8```ZX*_@/___[@!
+M````Z$+[___'19``````QD6.!NEC____OI3____HP?+__X!]K_\/A8T```!F
+MBT6MB$6,B&6@9?\U`````&6!#0```````P``_W6LZS!E_S4`````98$-````
+M```#``#_=:SHE?W__X]%K&:+1:V(18R(9:#_=:R`?:__=0?H90```.L%Z&,`
+M``"`O6______=0AE@`T%`````HUUN(U]@.A+W___OI3____H-/+__X]%K&6/
+M!0````"*1:TR1:Z(18SI5]+__[Z`____Z.3Q__^-=92-?8#H%-___[Z4____
+MZ.;Q___#Z-O___]E_S4`````98$-```````#``#H^\;__^@3^O__98\%````
+M`,.^N/___^B;\?__Z,W___^-=;B-?8#HQM[__[Z4____Z)CQ__]E@0T`````
+M``\``,:%=/___P7H0^7__^C+^?__C76XC7V4Z)7>__^^@/___^A^\?___T60
+MZ'_____#Z+#Z__]U&L9%K"N*18R(1:V-=8"-?;CH9M[__^F=`0``Z"O[__^`
+M?8X!=0N`?:__==_I?0$``(!]K_\/A-@!``"X_S\``"M%D(/X'GQ4?Q&!?8@`
+M`!"-=TERMH-]A`!TL#W_/P``?*EE@`T$````$&7V!0`````0=0F!19``8```
+MZXZ_@/___[@!````Z$KY___'19``````QD6.!NEO_____W6L9?\U`````&6!
+M)0````#_\___98$-```````#``!`Z,;[__^^@/___^AU\/__OI3____H:_#_
+M_^B8_O__OI3____H<_#__[Z`____Z&GP___HJ/[__V6/!0````"/1:QE@"4%
+M````_8"];_____\/A:4```!E@`T%`````NF8````C76`C7V4Z%'=___H@,7_
+M_^AR^/__C76XC7V`Z#S=__^^E/___^@E\/__QH5T____!>C$X___Z$SX__^-
+M=;B-?93H%MW__[Z`____Z/_O____19#H`/[__XUUN(U]E.CYW/__OH#____H
+MXN___\:%=/___P;H@>/__^@)^/__P^@+^?__=2W&1:PLQD6N`+ZX____Z+?O
+M__^`?:PL=`6*1:WK`XI%KHA%Q+^X____Z:3,___H<_G__X!]C@%U*X!]K_]U
+MRL=%N`````#'1;P`````QT7``````,=%Q````0#'1<@`````Z[J`?:__#X0H
+M_O__N/\_```K19"#^#Y\%7^,@7V(````@'<*@WV$``^$>?____]UK&7_-0``
+M``!E@24`````__/__V6!#0```````P``0.@M^O__Z!/]__^-=;B-?8#H$=S_
+M_^BP_O__98\%`````(]%K&6`)04```#]@+UO_____P^%*?___V6`#04````"
+MZ1S____H2_?__W4L,<"*98R)1:R^E/___^BZ[O__@'VO_W4%Z)/\__]FBT6M
+MB$6,B&6@Z=/.___H=_C__X!]C@%TT;C_/P``*T60@_@^?%)_#X%]B````(!W
+M1X-]A`!U03W_/P``?*QE@`T$````$&7V!0`````0=0F!19``8```ZY&_@/__
+M_[@!````Z*WV___'19``````QD6.!NER_____W6L9?\U`````&6!)0````#_
+M\___98$-```````#``"#^!Y\'W\1@7V(```0C7<4<@:#?80`=0PQV[Z`____
+MZ,3M__^<0.@$^?__G704OH#____HL.W__[Z4____Z*;M__^<Z-+[__^==!2^
+ME/___^BJ[?__OH#____HH.W__[ZX____Z'_M__]T!YSHTOO__YV^@/___^B#
+M[?__=`J^N/___^A@[?__Z#K]__^^@/___^AH[?__C76XC7V4Z(':__]ECP4`
+M````CT6LZ:O^__]FBT0]"&8+1#T&9@M$/01F"T0]`F8+1#T`=0'#9KC__\.+
+M1#T`"T0]!`M$/0AU`<.X_____\,QP(E$/0")1#T$B40]",-F,<!FB40]"&:)
+M1#T&9HE$/01FB40]`F:)1#T`PXM-J-#AZQFQ`;^X____ZQ"Q"+^4____ZP>Q
+M"+^`____L``QTM#(#[[`4+4"@/D@<EF`^6!R(70#9@G""U0]``M4/00+5#T(
+MB.")1#T`B40]!(E$/0A8PQX6'Q8'`>^)_HC+@^%@P>D%B,@+%H/&!.+Y9KD#
+M`"C!B,_SI8C!B.#SJX/O#"GO'V:)V5A74(M$/0`QVP^MPPG:BT0]!`^M1#T`
+M@\<$_LUU\%B(X`^M1#T`7_C#O[K____K%+$(OY;____K"[$(ZP*Q`;^"____
+M@/E0?@*Q4(C()'AT,E%7'F:89L'H`V9(N0D````!SP^_P"G!`>^)_BG&3A8?
+M%@?]\Z2(#XG!B?Y/\Z3\'U]9@^$'=!MFT60]`&;15#T"9M%4/01FT50]!F;1
+M5#T(XN7#]D0]"X!U&%>Y`0```(/'`NC/____7_],/1#V1#T+@,/HV____W3Y
+MP[^"____OI;____K8K^Z____ZP^_XO___^@%````OY;___^^@O___^M%OY;_
+M___K!;^"____ON[____K,K^6____ZP6_@O___[[B____ZQ^_XO___^L3O^[_
+M___K#+^6____ZP6_@O___[ZZ____`>X>%A\6!P'ON04```#S9J4?P[[R,P``
+MZ`H```"_N/___^EE\___Z"4```#I;][__[^"____Z!L```#I@][__[^6____
+MZ^_H!0```.E5P/__OY;___\>#NNJ````+G-Y;71A8@`N<W1R=&%B`"YS:'-T
+M<G1A8@`N=&5X=``N9&%T80`N8G-S````````````````````````````````
+M```````#``$``````+12`````````P`"``````"T4@````````,``P`!````
+M```````````1``$`"P```!@`````````$0`!`!L````<`````````!$``0`G
+M````M%(````````1``$``&9P95]S=&%R=`!F<&5?<F5G7W-E9VUE;G0`9G!E
+M7W)E8V]V97(`9G!E7V5N9```````````````````````````````````````
+M`````````````````!L````!````!P``````````$```M%(`````````````
+M!``````````A`````0````,```"T4@``M&(```````````````````0`````
+M````)P````@````#````M%(``+1B```````````````````$`````````!$`
+M```#``````````````"T8@``+````````````````0`````````!`````@``
+M````````````X&(``(`````&````!`````0````0````"0````,`````````
+<`````&!C```O```````````````!```````````0
+`
+end
diff --git a/i386/i386/fpe_linkage.c b/i386/i386/fpe_linkage.c
new file mode 100644
index 00000000..cac58e0b
--- /dev/null
+++ b/i386/i386/fpe_linkage.c
@@ -0,0 +1,359 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * Support routines for FP emulator.
+ */
+
+#include <fpe.h>
+
+#include <cpus.h>
+
+#include <mach/std_types.h>
+#include <mach/exception.h>
+#include <mach/thread_status.h>
+
+#include <kern/cpu_number.h>
+#include <kern/thread.h>
+
+#include <vm/vm_kern.h>
+
+#include <mach/machine/eflags.h>
+#include "vm_param.h"
+#include <i386/pmap.h>
+#include <i386/thread.h>
+#include <i386/fpu.h>
+#include "proc_reg.h"
+#include "seg.h"
+#include "idt.h"
+#include "gdt.h"
+
+#if NCPUS > 1
+#include <i386/mp_desc.h>
+#endif
+
+extern vm_offset_t kvtophys();
+
+/*
+ * Symbols exported from FPE emulator.
+ */
+extern char fpe_start[]; /* start of emulator text;
+ also emulation entry point */
+extern char fpe_end[]; /* end of emulator text */
+extern int fpe_reg_segment;
+ /* word holding segment number for
+ FPE register/status area */
+extern char fpe_recover[]; /* emulation fault recovery entry point */
+
+extern void fix_desc();
+
+#if NCPUS > 1
+#define curr_gdt(mycpu) (mp_gdt[mycpu])
+#define curr_idt(mycpu) (mp_desc_table[mycpu]->idt)
+#else
+#define curr_gdt(mycpu) (gdt)
+#define curr_idt(mycpu) (idt)
+#endif
+
+#define gdt_desc_p(mycpu,sel) \
+ ((struct real_descriptor *)&curr_gdt(mycpu)[sel_idx(sel)])
+#define idt_desc_p(mycpu,idx) \
+ ((struct real_gate *)&curr_idt(mycpu)[idx])
+
+void set_user_access(); /* forward */
+
+/*
+ * long pointer for calling FPE register recovery routine.
+ */
+struct long_ptr {
+ unsigned long offset;
+ unsigned short segment;
+};
+
+struct long_ptr fpe_recover_ptr;
+
+/*
+ * Initialize descriptors for FP emulator.
+ */
+void
+fpe_init()
+{
+ register struct real_descriptor *gdt_p;
+ register struct real_gate *idt_p;
+
+ /*
+ * Map in the pages for the FP emulator:
+ * read-only, user-accessible.
+ */
+ set_user_access(pmap_kernel(),
+ (vm_offset_t)fpe_start,
+ (vm_offset_t)fpe_end,
+ FALSE);
+
+ /*
+ * Put the USER_FPREGS segment value in the FP emulator.
+ */
+ fpe_reg_segment = USER_FPREGS;
+
+ /*
+ * Change exception 7 gate (coprocessor not present)
+ * to a trap gate to the FPE code segment.
+ */
+ idt_p = idt_desc_p(cpu_number(), 7);
+ idt_p->offset_low = 0; /* offset of FPE entry */
+ idt_p->offset_high = 0;
+ idt_p->selector = FPE_CS; /* FPE code segment */
+ idt_p->word_count = 0;
+ idt_p->access = ACC_P|ACC_PL_K|ACC_TRAP_GATE;
+ /* trap gate */
+ /* kernel privileges only,
+ so INT $7 does not call
+ the emulator */
+
+ /*
+ * Build GDT entry for FP code segment.
+ */
+ gdt_p = gdt_desc_p(cpu_number(), FPE_CS);
+ gdt_p->base_low = ((vm_offset_t) fpe_start) & 0xffff;
+ gdt_p->base_med = (((vm_offset_t) fpe_start) >> 16) & 0xff;
+ gdt_p->base_high = ((vm_offset_t) fpe_start) >> 24;
+ gdt_p->limit_low = (vm_offset_t) fpe_end
+ - (vm_offset_t) fpe_start
+ - 1;
+ gdt_p->limit_high = 0;
+ gdt_p->granularity = SZ_32;
+ gdt_p->access = ACC_P|ACC_PL_K|ACC_CODE_CR;
+ /* conforming segment,
+ usable by kernel */
+
+ /*
+ * Build GDT entry for user FP state area - template,
+ * since each thread has its own.
+ */
+ gdt_p = gdt_desc_p(cpu_number(), USER_FPREGS);
+ /* descriptor starts as 0 */
+ gdt_p->limit_low = sizeof(struct i386_fp_save)
+ + sizeof(struct i386_fp_regs)
+ - 1;
+ gdt_p->limit_high = 0;
+ gdt_p->granularity = 0;
+ gdt_p->access = ACC_PL_U|ACC_DATA_W;
+ /* start as "not present" */
+
+ /*
+ * Set up the recovery routine pointer
+ */
+ fpe_recover_ptr.offset = fpe_recover - fpe_start;
+ fpe_recover_ptr.segment = FPE_CS;
+
+ /*
+ * Set i386 to emulate coprocessor.
+ */
+ set_cr0((get_cr0() & ~CR0_MP) | CR0_EM);
+}
+
+/*
+ * Enable FPE use for a new thread.
+ * Allocates the FP save area.
+ */
+boolean_t
+fp_emul_error(regs)
+ struct i386_saved_state *regs;
+{
+ register struct i386_fpsave_state *ifps;
+ register vm_offset_t start_va;
+
+ if ((regs->err & 0xfffc) != (USER_FPREGS & ~SEL_PL))
+ return FALSE;
+
+ /*
+ * Make the FPU save area user-accessible (by FPE)
+ */
+ ifps = current_thread()->pcb->ims.ifps;
+ if (ifps == 0) {
+ /*
+ * No FP register state yet - allocate it.
+ */
+ fp_state_alloc();
+ ifps = current_thread()->pcb->ims.ifps;
+ }
+
+ panic("fp_emul_error: FP emulation is probably broken because of VM changes; fix! XXX");
+ start_va = (vm_offset_t) &ifps->fp_save_state;
+ set_user_access(current_map()->pmap,
+ start_va,
+ start_va + sizeof(struct i386_fp_save),
+ TRUE);
+
+ /*
+ * Enable FPE use for this thread
+ */
+ enable_fpe(ifps);
+
+ return TRUE;
+}
+
+/*
+ * Enable FPE use. ASSUME that kernel does NOT use FPU
+ * except to handle user exceptions.
+ */
+void
+enable_fpe(ifps)
+ register struct i386_fpsave_state *ifps;
+{
+ struct real_descriptor *dp;
+ vm_offset_t start_va;
+
+ dp = gdt_desc_p(cpu_number(), USER_FPREGS);
+ start_va = (vm_offset_t)&ifps->fp_save_state;
+
+ dp->base_low = start_va & 0xffff;
+ dp->base_med = (start_va >> 16) & 0xff;
+ dp->base_high = start_va >> 24;
+ dp->access |= ACC_P;
+}
+
+void
+disable_fpe()
+{
+ /*
+ * The kernel might be running with fs & gs segments
+ * which refer to USER_FPREGS, if we entered the kernel
+ * from a FP-using thread. We have to clear these segments
+ * lest we get a Segment Not Present trap. This would happen
+ * if the kernel took an interrupt or fault after clearing
+ * the present bit but before exiting to user space (which
+ * would reset fs & gs from the current user thread).
+ */
+
+ asm volatile("xorl %eax, %eax");
+ asm volatile("movw %ax, %fs");
+ asm volatile("movw %ax, %gs");
+
+ gdt_desc_p(cpu_number(), USER_FPREGS)->access &= ~ACC_P;
+}
+
+void
+set_user_access(pmap, start, end, writable)
+ pmap_t pmap;
+ vm_offset_t start;
+ vm_offset_t end;
+ boolean_t writable;
+{
+ register vm_offset_t va;
+ register pt_entry_t * dirbase = pmap->dirbase;
+ register pt_entry_t * ptep;
+ register pt_entry_t * pdep;
+
+ start = i386_trunc_page(start);
+ end = i386_round_page(end);
+
+ for (va = start; va < end; va += I386_PGBYTES) {
+
+ pdep = &dirbase[lin2pdenum(kvtolin(va))];
+ *pdep |= INTEL_PTE_USER;
+ ptep = (pt_entry_t *)ptetokv(*pdep);
+ ptep = &ptep[ptenum(va)];
+ *ptep |= INTEL_PTE_USER;
+ if (!writable)
+ *ptep &= ~INTEL_PTE_WRITE;
+ }
+}
+
+/*
+ * Route exception through emulator fixup routine if
+ * it occured within the emulator.
+ */
+extern void exception();
+
+void
+fpe_exception_fixup(exc, code, subcode)
+ int exc, code, subcode;
+{
+ thread_t thread = current_thread();
+ pcb_t pcb = thread->pcb;
+
+ if (pcb->iss.efl & EFL_VM) {
+ /*
+ * The emulator doesn`t handle V86 mode.
+ * If this is a GP fault on the emulator`s
+ * code segment, change it to an FP not present
+ * fault.
+ */
+ if (exc == EXC_BAD_INSTRUCTION
+ && code == EXC_I386_GPFLT
+ && subcode == FPE_CS + 1)
+ {
+ exc = EXC_ARITHMETIC; /* arithmetic error: */
+ code = EXC_I386_NOEXT; /* no FPU */
+ subcode = 0;
+ }
+ }
+ else
+ if ((pcb->iss.cs & 0xfffc) == FPE_CS) {
+ /*
+ * Pass registers to emulator,
+ * to let it fix them up.
+ * The emulator fixup routine knows about
+ * an i386_thread_state.
+ */
+ struct i386_thread_state tstate;
+ unsigned int count;
+
+ count = i386_THREAD_STATE_COUNT;
+ (void) thread_getstatus(thread,
+ i386_REGS_SEGS_STATE,
+ (thread_state_t) &tstate,
+ &count);
+
+ /*
+ * long call to emulator register recovery routine
+ */
+ asm volatile("pushl %0; lcall %1; addl $4,%%esp"
+ :
+ : "r" (&tstate),
+ "m" (*(char *)&fpe_recover_ptr) );
+
+ (void) thread_setstatus(thread,
+ i386_REGS_SEGS_STATE,
+ (thread_state_t) &tstate,
+ count);
+ /*
+ * In addition, check for a GP fault on 'int 16' in
+ * the emulator, since the interrupt gate is protected.
+ * If so, change it to an arithmetic error.
+ */
+ if (exc == EXC_BAD_INSTRUCTION
+ && code == EXC_I386_GPFLT
+ && subcode == 8*16+2) /* idt[16] */
+ {
+ exc = EXC_ARITHMETIC;
+ code = EXC_I386_EXTERR;
+ subcode = pcb->ims.ifps->fp_save_state.fp_status;
+ }
+ }
+ exception(exc, code, subcode);
+}
diff --git a/i386/i386/fpu.c b/i386/i386/fpu.c
new file mode 100644
index 00000000..dc49a6a4
--- /dev/null
+++ b/i386/i386/fpu.c
@@ -0,0 +1,750 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992-1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Support for 80387 floating point or FP emulator.
+ */
+#include <cpus.h>
+#include <fpe.h>
+#include <platforms.h>
+
+#include <mach/exception.h>
+#include <mach/machine/thread_status.h>
+#include <mach/machine/fp_reg.h>
+
+#include <machine/machspl.h> /* spls */
+#include <kern/mach_param.h>
+#include <kern/thread.h>
+#include <kern/zalloc.h>
+
+#include <i386/thread.h>
+#include <i386/fpu.h>
+#include "cpu_number.h"
+
+#if 0
+#include <i386/ipl.h>
+extern int curr_ipl;
+#define ASSERT_IPL(L) \
+{ \
+ if (curr_ipl != L) { \
+ printf("IPL is %d, expected %d\n", curr_ipl, L); \
+ panic("fpu: wrong ipl"); \
+ } \
+}
+#else
+#define ASSERT_IPL(L)
+#endif
+
+extern void i386_exception();
+
+int fp_kind = FP_387; /* 80387 present */
+zone_t ifps_zone; /* zone for FPU save area */
+
+#if NCPUS == 1
+volatile thread_t fp_thread = THREAD_NULL;
+ /* thread whose state is in FPU */
+ /* always THREAD_NULL if emulating
+ FPU */
+volatile thread_t fp_intr_thread = THREAD_NULL;
+
+
+#define clear_fpu() \
+ { \
+ set_ts(); \
+ fp_thread = THREAD_NULL; \
+ }
+
+#else /* NCPUS > 1 */
+#define clear_fpu() \
+ { \
+ set_ts(); \
+ }
+
+#endif
+
+
+/*
+ * Look for FPU and initialize it.
+ * Called on each CPU.
+ */
+void
+init_fpu()
+{
+ unsigned short status, control;
+
+ /*
+ * Check for FPU by initializing it,
+ * then trying to read the correct bit patterns from
+ * the control and status registers.
+ */
+ set_cr0(get_cr0() & ~(CR0_EM|CR0_TS)); /* allow use of FPU */
+
+ fninit();
+ status = fnstsw();
+ fnstcw(&control);
+
+ if ((status & 0xff) == 0 &&
+ (control & 0x103f) == 0x3f)
+ {
+ /*
+ * We have a FPU of some sort.
+ * Compare -infinity against +infinity
+ * to check whether we have a 287 or a 387.
+ */
+ volatile double fp_infinity, fp_one, fp_zero;
+ fp_one = 1.0;
+ fp_zero = 0.0;
+ fp_infinity = fp_one / fp_zero;
+ if (fp_infinity == -fp_infinity) {
+ /*
+ * We have an 80287.
+ */
+ fp_kind = FP_287;
+ asm volatile(".byte 0xdb; .byte 0xe4"); /* fnsetpm */
+ }
+ else {
+ /*
+ * We have a 387.
+ */
+ fp_kind = FP_387;
+ }
+ /*
+ * Trap wait instructions. Turn off FPU for now.
+ */
+ set_cr0(get_cr0() | CR0_TS | CR0_MP);
+ }
+ else {
+#if FPE
+ /*
+ * Use the floating-point emulator.
+ */
+ fp_kind = FP_SOFT;
+ fpe_init();
+#else /* no fpe */
+ /*
+ * NO FPU.
+ */
+ fp_kind = FP_NO;
+ set_cr0(get_cr0() | CR0_EM);
+#endif
+ }
+}
+
+/*
+ * Initialize FP handling.
+ */
+void
+fpu_module_init()
+{
+ ifps_zone = zinit(sizeof(struct i386_fpsave_state),
+ THREAD_MAX * sizeof(struct i386_fpsave_state),
+ THREAD_CHUNK * sizeof(struct i386_fpsave_state),
+ 0, "i386 fpsave state");
+}
+
+/*
+ * Free a FPU save area.
+ * Called only when thread terminating - no locking necessary.
+ */
+void
+fp_free(fps)
+ struct i386_fpsave_state *fps;
+{
+ASSERT_IPL(SPL0);
+#if NCPUS == 1
+ if ((fp_thread != THREAD_NULL) && (fp_thread->pcb->ims.ifps == fps)) {
+ /*
+ * Make sure we don't get FPU interrupts later for
+ * this thread
+ */
+ fwait();
+
+ /* Mark it free and disable access */
+ clear_fpu();
+ }
+#endif /* NCPUS == 1 */
+ zfree(ifps_zone, (vm_offset_t) fps);
+}
+
+/*
+ * Set the floating-point state for a thread.
+ * If the thread is not the current thread, it is
+ * not running (held). Locking needed against
+ * concurrent fpu_set_state or fpu_get_state.
+ */
+kern_return_t
+fpu_set_state(thread, state)
+ thread_t thread;
+ struct i386_float_state *state;
+{
+ register pcb_t pcb = thread->pcb;
+ register struct i386_fpsave_state *ifps;
+ register struct i386_fpsave_state *new_ifps;
+
+ASSERT_IPL(SPL0);
+ if (fp_kind == FP_NO)
+ return KERN_FAILURE;
+
+#if NCPUS == 1
+
+ /*
+ * If this thread`s state is in the FPU,
+ * discard it; we are replacing the entire
+ * FPU state.
+ */
+ if (fp_thread == thread) {
+ fwait(); /* wait for possible interrupt */
+ clear_fpu(); /* no state in FPU */
+ }
+#endif
+
+ if (state->initialized == 0) {
+ /*
+ * new FPU state is 'invalid'.
+ * Deallocate the fp state if it exists.
+ */
+ simple_lock(&pcb->lock);
+ ifps = pcb->ims.ifps;
+ pcb->ims.ifps = 0;
+ simple_unlock(&pcb->lock);
+
+ if (ifps != 0) {
+ zfree(ifps_zone, (vm_offset_t) ifps);
+ }
+ }
+ else {
+ /*
+ * Valid state. Allocate the fp state if there is none.
+ */
+ register struct i386_fp_save *user_fp_state;
+ register struct i386_fp_regs *user_fp_regs;
+
+ user_fp_state = (struct i386_fp_save *) &state->hw_state[0];
+ user_fp_regs = (struct i386_fp_regs *)
+ &state->hw_state[sizeof(struct i386_fp_save)];
+
+ new_ifps = 0;
+ Retry:
+ simple_lock(&pcb->lock);
+ ifps = pcb->ims.ifps;
+ if (ifps == 0) {
+ if (new_ifps == 0) {
+ simple_unlock(&pcb->lock);
+ new_ifps = (struct i386_fpsave_state *) zalloc(ifps_zone);
+ goto Retry;
+ }
+ ifps = new_ifps;
+ new_ifps = 0;
+ pcb->ims.ifps = ifps;
+ }
+
+ /*
+ * Ensure that reserved parts of the environment are 0.
+ */
+ bzero((char *)&ifps->fp_save_state, sizeof(struct i386_fp_save));
+
+ ifps->fp_save_state.fp_control = user_fp_state->fp_control;
+ ifps->fp_save_state.fp_status = user_fp_state->fp_status;
+ ifps->fp_save_state.fp_tag = user_fp_state->fp_tag;
+ ifps->fp_save_state.fp_eip = user_fp_state->fp_eip;
+ ifps->fp_save_state.fp_cs = user_fp_state->fp_cs;
+ ifps->fp_save_state.fp_opcode = user_fp_state->fp_opcode;
+ ifps->fp_save_state.fp_dp = user_fp_state->fp_dp;
+ ifps->fp_save_state.fp_ds = user_fp_state->fp_ds;
+
+#if FPE
+ if (fp_kind == FP_SOFT) {
+ /*
+ * The emulator stores the registers by physical
+ * register number, not from top-of-stack.
+ * Shuffle the registers into the correct order.
+ */
+ register char *src; /* user regs */
+ register char *dst; /* kernel regs */
+ int i;
+
+ src = (char *)user_fp_regs;
+ dst = (char *)&ifps->fp_regs;
+ i = (ifps->fp_save_state.fp_status & FPS_TOS)
+ >> FPS_TOS_SHIFT; /* physical register
+ for st(0) */
+ if (i == 0)
+ bcopy(src, dst, 8 * 10);
+ else {
+ bcopy(src,
+ dst + 10 * i,
+ 10 * (8 - i));
+ bcopy(src + 10 * (8 - i),
+ dst,
+ 10 * i);
+ }
+ }
+ else
+ ifps->fp_regs = *user_fp_regs;
+#else /* no FPE */
+ ifps->fp_regs = *user_fp_regs;
+#endif /* FPE */
+
+ simple_unlock(&pcb->lock);
+ if (new_ifps != 0)
+ zfree(ifps_zone, (vm_offset_t) ifps);
+ }
+
+ return KERN_SUCCESS;
+}
+
+/*
+ * Get the floating-point state for a thread.
+ * If the thread is not the current thread, it is
+ * not running (held). Locking needed against
+ * concurrent fpu_set_state or fpu_get_state.
+ */
+kern_return_t
+fpu_get_state(thread, state)
+ thread_t thread;
+ register struct i386_float_state *state;
+{
+ register pcb_t pcb = thread->pcb;
+ register struct i386_fpsave_state *ifps;
+
+ASSERT_IPL(SPL0);
+ if (fp_kind == FP_NO)
+ return KERN_FAILURE;
+
+ simple_lock(&pcb->lock);
+ ifps = pcb->ims.ifps;
+ if (ifps == 0) {
+ /*
+ * No valid floating-point state.
+ */
+ simple_unlock(&pcb->lock);
+ bzero((char *)state, sizeof(struct i386_float_state));
+ return KERN_SUCCESS;
+ }
+
+ /* Make sure we`ve got the latest fp state info */
+ clear_ts();
+ fp_save(thread);
+ clear_fpu();
+
+ state->fpkind = fp_kind;
+ state->exc_status = 0;
+
+ {
+ register struct i386_fp_save *user_fp_state;
+ register struct i386_fp_regs *user_fp_regs;
+
+ state->initialized = ifps->fp_valid;
+
+ user_fp_state = (struct i386_fp_save *) &state->hw_state[0];
+ user_fp_regs = (struct i386_fp_regs *)
+ &state->hw_state[sizeof(struct i386_fp_save)];
+
+ /*
+ * Ensure that reserved parts of the environment are 0.
+ */
+ bzero((char *)user_fp_state, sizeof(struct i386_fp_save));
+
+ user_fp_state->fp_control = ifps->fp_save_state.fp_control;
+ user_fp_state->fp_status = ifps->fp_save_state.fp_status;
+ user_fp_state->fp_tag = ifps->fp_save_state.fp_tag;
+ user_fp_state->fp_eip = ifps->fp_save_state.fp_eip;
+ user_fp_state->fp_cs = ifps->fp_save_state.fp_cs;
+ user_fp_state->fp_opcode = ifps->fp_save_state.fp_opcode;
+ user_fp_state->fp_dp = ifps->fp_save_state.fp_dp;
+ user_fp_state->fp_ds = ifps->fp_save_state.fp_ds;
+
+#if FPE
+ if (fp_kind == FP_SOFT) {
+ /*
+ * The emulator stores the registers by physical
+ * register number, not from top-of-stack.
+ * Shuffle the registers into the correct order.
+ */
+ register char *src; /* kernel regs */
+ register char *dst; /* user regs */
+ int i;
+
+ src = (char *)&ifps->fp_regs;
+ dst = (char *)user_fp_regs;
+ i = (ifps->fp_save_state.fp_status & FPS_TOS)
+ >> FPS_TOS_SHIFT; /* physical register
+ for st(0) */
+ if (i == 0)
+ bcopy(src, dst, 8 * 10);
+ else {
+ bcopy(src + 10 * i,
+ dst,
+ 10 * (8 - i));
+ bcopy(src,
+ dst + 10 * (8 - i),
+ 10 * i);
+ }
+ }
+ else
+ *user_fp_regs = ifps->fp_regs;
+#else /* no FPE */
+ *user_fp_regs = ifps->fp_regs;
+#endif /* FPE */
+ }
+ simple_unlock(&pcb->lock);
+
+ return KERN_SUCCESS;
+}
+
+/*
+ * Initialize FPU.
+ *
+ * Raise exceptions for:
+ * invalid operation
+ * divide by zero
+ * overflow
+ *
+ * Use 53-bit precision.
+ */
+void fpinit()
+{
+ unsigned short control;
+
+ASSERT_IPL(SPL0);
+ clear_ts();
+ fninit();
+ fnstcw(&control);
+ control &= ~(FPC_PC|FPC_RC); /* Clear precision & rounding control */
+ control |= (FPC_PC_53 | /* Set precision */
+ FPC_RC_RN | /* round-to-nearest */
+ FPC_ZE | /* Suppress zero-divide */
+ FPC_OE | /* and overflow */
+ FPC_UE | /* underflow */
+ FPC_IE | /* Allow NaNQs and +-INF */
+ FPC_DE | /* Allow denorms as operands */
+ FPC_PE); /* No trap for precision loss */
+ fldcw(control);
+}
+
+/*
+ * Coprocessor not present.
+ */
+fpnoextflt()
+{
+ /*
+ * Enable FPU use.
+ */
+ASSERT_IPL(SPL0);
+ clear_ts();
+#if NCPUS == 1
+
+ /*
+ * If this thread`s state is in the FPU, we are done.
+ */
+ if (fp_thread == current_thread())
+ return;
+
+ /* Make sure we don't do fpsave() in fp_intr while doing fpsave()
+ * here if the current fpu instruction generates an error.
+ */
+ fwait();
+ /*
+ * If another thread`s state is in the FPU, save it.
+ */
+ if (fp_thread != THREAD_NULL) {
+ fp_save(fp_thread);
+ }
+
+ /*
+ * Give this thread the FPU.
+ */
+ fp_thread = current_thread();
+
+#endif /* NCPUS == 1 */
+
+ /*
+ * Load this thread`s state into the FPU.
+ */
+ fp_load(current_thread());
+}
+
+/*
+ * FPU overran end of segment.
+ * Re-initialize FPU. Floating point state is not valid.
+ */
+fpextovrflt()
+{
+ register thread_t thread = current_thread();
+ register pcb_t pcb;
+ register struct i386_fpsave_state *ifps;
+
+#if NCPUS == 1
+
+ /*
+ * Is exception for the currently running thread?
+ */
+ if (fp_thread != thread) {
+ /* Uh oh... */
+ panic("fpextovrflt");
+ }
+#endif
+
+ /*
+ * This is a non-recoverable error.
+ * Invalidate the thread`s FPU state.
+ */
+ pcb = thread->pcb;
+ simple_lock(&pcb->lock);
+ ifps = pcb->ims.ifps;
+ pcb->ims.ifps = 0;
+ simple_unlock(&pcb->lock);
+
+ /*
+ * Re-initialize the FPU.
+ */
+ clear_ts();
+ fninit();
+
+ /*
+ * And disable access.
+ */
+ clear_fpu();
+
+ if (ifps)
+ zfree(ifps_zone, (vm_offset_t) ifps);
+
+ /*
+ * Raise exception.
+ */
+ i386_exception(EXC_BAD_ACCESS, VM_PROT_READ|VM_PROT_EXECUTE, 0);
+ /*NOTREACHED*/
+}
+
+/*
+ * FPU error. Called by AST.
+ */
+fpexterrflt()
+{
+ register thread_t thread = current_thread();
+
+ASSERT_IPL(SPL0);
+#if NCPUS == 1
+ /*
+ * Since FPU errors only occur on ESC or WAIT instructions,
+ * the current thread should own the FPU. If it didn`t,
+ * we should have gotten the task-switched interrupt first.
+ */
+ if (fp_thread != THREAD_NULL) {
+ panic("fpexterrflt");
+ return;
+ }
+
+ /*
+ * Check if we got a context switch between the interrupt and the AST
+ * This can happen if the interrupt arrived after the FPU AST was
+ * checked. In this case, raise the exception in fp_load when this
+ * thread next time uses the FPU. Remember exception condition in
+ * fp_valid (extended boolean 2).
+ */
+ if (fp_intr_thread != thread) {
+ if (fp_intr_thread == THREAD_NULL) {
+ panic("fpexterrflt: fp_intr_thread == THREAD_NULL");
+ return;
+ }
+ fp_intr_thread->pcb->ims.ifps->fp_valid = 2;
+ fp_intr_thread = THREAD_NULL;
+ return;
+ }
+ fp_intr_thread = THREAD_NULL;
+#else /* NCPUS == 1 */
+ /*
+ * Save the FPU state and turn off the FPU.
+ */
+ fp_save(thread);
+#endif /* NCPUS == 1 */
+
+ /*
+ * Raise FPU exception.
+ * Locking not needed on pcb->ims.ifps,
+ * since thread is running.
+ */
+ i386_exception(EXC_ARITHMETIC,
+ EXC_I386_EXTERR,
+ thread->pcb->ims.ifps->fp_save_state.fp_status);
+ /*NOTREACHED*/
+}
+
+/*
+ * Save FPU state.
+ *
+ * Locking not needed:
+ * . if called from fpu_get_state, pcb already locked.
+ * . if called from fpnoextflt or fp_intr, we are single-cpu
+ * . otherwise, thread is running.
+ */
+fp_save(thread)
+ register thread_t thread;
+{
+ register pcb_t pcb = thread->pcb;
+ register struct i386_fpsave_state *ifps = pcb->ims.ifps;
+
+ if (ifps != 0 && !ifps->fp_valid) {
+ /* registers are in FPU */
+ ifps->fp_valid = TRUE;
+ fnsave(&ifps->fp_save_state);
+ }
+}
+
+/*
+ * Restore FPU state from PCB.
+ *
+ * Locking not needed; always called on the current thread.
+ */
+fp_load(thread)
+ register thread_t thread;
+{
+ register pcb_t pcb = thread->pcb;
+ register struct i386_fpsave_state *ifps;
+
+ASSERT_IPL(SPL0);
+ ifps = pcb->ims.ifps;
+ if (ifps == 0) {
+ ifps = (struct i386_fpsave_state *) zalloc(ifps_zone);
+ bzero(ifps, sizeof *ifps);
+ pcb->ims.ifps = ifps;
+ fpinit();
+#if 1
+/*
+ * I'm not sure this is needed. Does the fpu regenerate the interrupt in
+ * frstor or not? Without this code we may miss some exceptions, with it
+ * we might send too many exceptions.
+ */
+ } else if (ifps->fp_valid == 2) {
+ /* delayed exception pending */
+
+ ifps->fp_valid = TRUE;
+ clear_fpu();
+ /*
+ * Raise FPU exception.
+ * Locking not needed on pcb->ims.ifps,
+ * since thread is running.
+ */
+ i386_exception(EXC_ARITHMETIC,
+ EXC_I386_EXTERR,
+ thread->pcb->ims.ifps->fp_save_state.fp_status);
+ /*NOTREACHED*/
+#endif
+ } else {
+ frstor(ifps->fp_save_state);
+ }
+ ifps->fp_valid = FALSE; /* in FPU */
+}
+
+/*
+ * Allocate and initialize FP state for current thread.
+ * Don't load state.
+ *
+ * Locking not needed; always called on the current thread.
+ */
+void
+fp_state_alloc()
+{
+ pcb_t pcb = current_thread()->pcb;
+ struct i386_fpsave_state *ifps;
+
+ ifps = (struct i386_fpsave_state *)zalloc(ifps_zone);
+ bzero(ifps, sizeof *ifps);
+ pcb->ims.ifps = ifps;
+
+ ifps->fp_valid = TRUE;
+ ifps->fp_save_state.fp_control = (0x037f
+ & ~(FPC_IM|FPC_ZM|FPC_OM|FPC_PC))
+ | (FPC_PC_53|FPC_IC_AFF);
+ ifps->fp_save_state.fp_status = 0;
+ ifps->fp_save_state.fp_tag = 0xffff; /* all empty */
+}
+
+#if AT386 || PS2
+/*
+ * Handle a coprocessor error interrupt on the AT386.
+ * This comes in on line 5 of the slave PIC at SPL1.
+ */
+fpintr()
+{
+ spl_t s;
+ thread_t thread = current_thread();
+
+ASSERT_IPL(SPL1);
+ /*
+ * Turn off the extended 'busy' line.
+ */
+ outb(0xf0, 0);
+
+ /*
+ * Save the FPU context to the thread using it.
+ */
+#if NCPUS == 1
+ if (fp_thread == THREAD_NULL) {
+ printf("fpintr: FPU not belonging to anyone!\n");
+ clear_ts();
+ fninit();
+ clear_fpu();
+ return;
+ }
+
+ if (fp_thread != thread) {
+ /*
+ * FPU exception is for a different thread.
+ * When that thread again uses the FPU an exception will be
+ * raised in fp_load. Remember the condition in fp_valid (== 2).
+ */
+ clear_ts();
+ fp_save(fp_thread);
+ fp_thread->pcb->ims.ifps->fp_valid = 2;
+ fninit();
+ clear_fpu();
+ /* leave fp_intr_thread THREAD_NULL */
+ return;
+ }
+ if (fp_intr_thread != THREAD_NULL)
+ panic("fp_intr: already caught intr");
+ fp_intr_thread = thread;
+#endif /* NCPUS == 1 */
+
+ clear_ts();
+ fp_save(thread);
+ fninit();
+ clear_fpu();
+
+ /*
+ * Since we are running on the interrupt stack, we must
+ * signal the thread to take the exception when we return
+ * to user mode. Use an AST to do this.
+ *
+ * Don`t set the thread`s AST field. If the thread is
+ * descheduled before it takes the AST, it will notice
+ * the FPU error when it reloads its FPU state.
+ */
+ s = splsched();
+ ast_on(cpu_number(), AST_I386_FP);
+ splx(s);
+}
+#endif /* AT386 || PS2 */
diff --git a/i386/i386/fpu.h b/i386/i386/fpu.h
new file mode 100644
index 00000000..7db1a8ef
--- /dev/null
+++ b/i386/i386/fpu.h
@@ -0,0 +1,130 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_FPU_H_
+#define _I386_FPU_H_
+
+/*
+ * Macro definitions for routines to manipulate the
+ * floating-point processor.
+ */
+
+#include <cpus.h>
+#include <fpe.h>
+#include <i386/proc_reg.h>
+#include <i386/thread.h>
+
+/*
+ * FPU instructions.
+ */
+#define fninit() \
+ asm volatile("fninit")
+
+#define fnstcw(control) \
+ asm("fnstcw %0" : "=m" (*(unsigned short *)(control)))
+
+#define fldcw(control) \
+ asm volatile("fldcw %0" : : "m" (*(unsigned short *) &(control)) )
+
+#define fnstsw() \
+ ({ \
+ unsigned short _status__; \
+ asm("fnstsw %0" : "=ma" (_status__)); \
+ _status__; \
+ })
+
+#define fnclex() \
+ asm volatile("fnclex")
+
+#define fnsave(state) \
+ asm volatile("fnsave %0" : "=m" (*state))
+
+#define frstor(state) \
+ asm volatile("frstor %0" : : "m" (state))
+
+#define fwait() \
+ asm("fwait");
+
+/*
+ * If floating-point instructions are emulated,
+ * we must load the floating-point register selector
+ * when switching to a new thread.
+ */
+#if FPE
+extern void disable_fpe();
+extern void enable_fpe();
+
+#define fpu_save_context(thread) \
+ { \
+ if (fp_kind == FP_SOFT) \
+ disable_fpe(); \
+ else \
+ set_ts(); \
+ }
+
+#define fpu_load_context(pcb) \
+ { \
+ register struct i386_fpsave_state *ifps; \
+ if (fp_kind == FP_SOFT && (ifps = pcb->ims.ifps) != 0) \
+ enable_fpe(ifps); \
+ }
+
+#else /* no FPE */
+
+#define fpu_load_context(pcb)
+
+/*
+ * Save thread`s FPU context.
+ * If only one CPU, we just set the task-switched bit,
+ * to keep the new thread from using the coprocessor.
+ * If multiple CPUs, we save the entire state.
+ */
+#if NCPUS > 1
+#define fpu_save_context(thread) \
+ { \
+ register struct i386_fpsave_state *ifps; \
+ ifps = (thread)->pcb->ims.ifps; \
+ if (ifps != 0 && !ifps->fp_valid) { \
+ /* registers are in FPU - save to memory */ \
+ ifps->fp_valid = TRUE; \
+ fnsave(&ifps->fp_save_state); \
+ set_ts(); \
+ } \
+ }
+
+#else /* NCPUS == 1 */
+#define fpu_save_context(thread) \
+ { \
+ set_ts(); \
+ }
+
+#endif /* NCPUS == 1 */
+
+#endif /* no FPE */
+
+extern int fp_kind;
+
+#endif /* _I386_FPU_H_ */
diff --git a/i386/i386/gdt.c b/i386/i386/gdt.c
new file mode 100644
index 00000000..d8551110
--- /dev/null
+++ b/i386/i386/gdt.c
@@ -0,0 +1,88 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * Copyright (c) 1991 IBM Corporation
+ * 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,
+ * and that the name IBM not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written
+ * prior permission.
+ *
+ * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Global descriptor table.
+ */
+#include <mach/machine/vm_types.h>
+
+#include <platforms.h>
+
+#include "vm_param.h"
+#include "seg.h"
+#include "gdt.h"
+
+#if PS2
+extern unsigned long abios_int_return;
+extern unsigned long abios_th_return;
+extern char intstack[];
+#endif /* PS2 */
+
+struct real_descriptor gdt[GDTSZ];
+
+void
+gdt_init()
+{
+ /* Initialize the kernel code and data segment descriptors. */
+ fill_gdt_descriptor(KERNEL_CS,
+ LINEAR_MIN_KERNEL_ADDRESS,
+ LINEAR_MAX_KERNEL_ADDRESS - LINEAR_MIN_KERNEL_ADDRESS - 1,
+ ACC_PL_K|ACC_CODE_R, SZ_32);
+ fill_gdt_descriptor(KERNEL_DS,
+ LINEAR_MIN_KERNEL_ADDRESS,
+ LINEAR_MAX_KERNEL_ADDRESS - LINEAR_MIN_KERNEL_ADDRESS - 1,
+ ACC_PL_K|ACC_DATA_W, SZ_32);
+
+ /* Load the new GDT. */
+ {
+ struct pseudo_descriptor pdesc;
+
+ pdesc.limit = sizeof(gdt)-1;
+ pdesc.linear_base = kvtolin(&gdt);
+ lgdt(&pdesc);
+ }
+
+ /* Reload all the segment registers from the new GDT.
+ We must load ds and es with 0 before loading them with KERNEL_DS
+ because some processors will "optimize out" the loads
+ if the previous selector values happen to be the same. */
+ asm volatile("
+ ljmp %0,$1f
+ 1:
+ movw %w2,%%ds
+ movw %w2,%%es
+ movw %w2,%%fs
+ movw %w2,%%gs
+
+ movw %w1,%%ds
+ movw %w1,%%es
+ movw %w1,%%ss
+ " : : "i" (KERNEL_CS), "r" (KERNEL_DS), "r" (0));
+}
+
diff --git a/i386/i386/gdt.h b/i386/i386/gdt.h
new file mode 100644
index 00000000..10d47624
--- /dev/null
+++ b/i386/i386/gdt.h
@@ -0,0 +1,72 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * Copyright (c) 1991 IBM Corporation
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory (CSL).
+ * 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,
+ * and that the name IBM not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written
+ * prior permission.
+ *
+ * CARNEGIE MELLON, IBM, AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON, IBM, AND CSL DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_GDT_
+#define _I386_GDT_
+
+#include "seg.h"
+
+/*
+ * Kernel descriptors for Mach - 32-bit flat address space.
+ */
+#define KERNEL_CS 0x08 /* kernel code */
+#define KERNEL_DS 0x10 /* kernel data */
+#define KERNEL_LDT 0x18 /* master LDT */
+#define KERNEL_TSS 0x20 /* master TSS (uniprocessor) */
+#define USER_LDT 0x28 /* place for per-thread LDT */
+#define USER_TSS 0x30 /* place for per-thread TSS
+ that holds IO bitmap */
+#define FPE_CS 0x38 /* floating-point emulator code */
+#define USER_FPREGS 0x40 /* user-mode access to saved
+ floating-point registers */
+
+#ifdef PS2
+#define ABIOS_INT_RET 0x48 /* 16 bit return selector for ABIOS */
+#define ABIOS_TH_RET 0x50 /* 16 bit return selector for ABIOS */
+#define ABIOS_INT_SS 0x58 /* ABIOS interrupt stack selector */
+#define ABIOS_TH_SS 0x60 /* ABIOS current stack selector */
+#define ABIOS_FIRST_AVAIL_SEL \
+ 0x68 /* first selector for ABIOS
+ to allocate */
+#define GDTSZ 0x300 /* size of gdt table */
+#else /* PS2 */
+#define GDTSZ 11
+#endif /* PS2 */
+
+
+extern struct real_descriptor gdt[GDTSZ];
+
+/* Fill a segment descriptor in the GDT. */
+#define fill_gdt_descriptor(segment, base, limit, access, sizebits) \
+ fill_descriptor(&gdt[segment/8], base, limit, access, sizebits)
+
+#endif _I386_GDT_
diff --git a/i386/i386/hardclock.c b/i386/i386/hardclock.c
new file mode 100644
index 00000000..b4804da3
--- /dev/null
+++ b/i386/i386/hardclock.c
@@ -0,0 +1,99 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * Copyright (c) 1991 IBM Corporation
+ * 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,
+ * and that the name IBM not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written
+ * prior permission.
+ *
+ * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Clock interrupt.
+ */
+#include <mach/machine/eflags.h>
+
+#include <platforms.h>
+
+#include <kern/time_out.h>
+#include <i386/thread.h>
+
+#ifdef SYMMETRY
+#include <sqt/intctl.h>
+#endif
+#if defined(AT386) || defined(iPSC386)
+#include <i386/ipl.h>
+#endif
+#ifdef PS2
+#include <i386/pic.h>
+#include <i386/pio.h>
+#endif PS2
+
+extern void clock_interrupt();
+extern char return_to_iret[];
+
+void
+#ifdef PS2
+hardclock(iunit, ivect, old_ipl, ret_addr, regs)
+ int iunit; /* 'unit' number */
+ int ivect; /* interrupt number */
+#else /* PS2 */
+hardclock(iunit, old_ipl, ret_addr, regs)
+ int iunit; /* 'unit' number */
+ int old_ipl; /* old interrupt level */
+#endif /* PS2 */
+ char * ret_addr; /* return address in interrupt handler */
+ struct i386_interrupt_state *regs;
+ /* saved registers */
+{
+ if (ret_addr == return_to_iret)
+ /*
+ * Interrupt from user mode or from thread stack.
+ */
+ clock_interrupt(tick, /* usec per tick */
+ (regs->efl & EFL_VM) || /* user mode */
+ ((regs->cs & 0x03) != 0), /* user mode */
+#if defined(PS2) || defined(LINUX_DEV)
+ FALSE /* ignore SPL0 */
+#else /* PS2 */
+ old_ipl == SPL0 /* base priority */
+#endif /* PS2 */
+ );
+ else
+ /*
+ * Interrupt from interrupt stack.
+ */
+ clock_interrupt(tick, /* usec per tick */
+ FALSE, /* kernel mode */
+ FALSE); /* not SPL0 */
+
+#ifdef LINUX_DEV
+ linux_timer_intr();
+#endif
+
+#ifdef PS2
+ /*
+ * Reset the clock interrupt line.
+ */
+ outb(0x61, inb(0x61) | 0x80);
+#endif /* PS2 */
+}
diff --git a/i386/i386/i386asm.sym b/i386/i386/i386asm.sym
new file mode 100644
index 00000000..e38a1bd6
--- /dev/null
+++ b/i386/i386/i386asm.sym
@@ -0,0 +1,139 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * Copyright (c) 1991 IBM Corporation
+ * 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,
+ * and that the name IBM not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written
+ * prior permission.
+ *
+ * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <platforms.h>
+#include <cpus.h>
+#include <mach_kdb.h>
+#include <stat_time.h>
+
+/*
+ * Pass field offsets to assembly code.
+ */
+#include <sys/reboot.h>
+
+#include <kern/thread.h>
+#include <kern/task.h>
+#include <kern/syscall_emulation.h>
+#include <i386/thread.h>
+#include <i386/pmap.h>
+#include "vm_param.h"
+#include "seg.h"
+#include "tss.h"
+#include "idt.h"
+#include "gdt.h"
+#include "ldt.h"
+#include "mp_desc.h"
+
+
+offset thread th pcb
+offset thread th task
+offset thread th recover
+offset thread th kernel_stack
+offset thread th swap_func
+
+offset task task eml_dispatch TASK_EMUL
+
+offset eml_dispatch eml disp_min DISP_MIN
+offset eml_dispatch eml disp_count DISP_COUNT
+offset eml_dispatch eml disp_vector DISP_VECTOR
+
+expr &STACK_IKS(0)->k_ebx KSS_EBX
+expr &STACK_IKS(0)->k_esp KSS_ESP
+expr &STACK_IKS(0)->k_ebp KSS_EBP
+expr &STACK_IKS(0)->k_esi KSS_ESI
+expr &STACK_IKS(0)->k_edi KSS_EDI
+expr &STACK_IKS(0)->k_eip KSS_EIP
+size i386_kernel_state iks
+
+size i386_exception_link iel
+
+offset i386_saved_state r cs
+offset i386_saved_state r uesp
+offset i386_saved_state r eax
+offset i386_saved_state r trapno
+offset i386_saved_state r err
+offset i386_saved_state r efl R_EFLAGS
+offset i386_saved_state r eip
+offset i386_saved_state r cr2
+
+offset i386_interrupt_state i eip
+offset i386_interrupt_state i cs
+offset i386_interrupt_state i efl
+
+offset i386_tss tss esp0
+offset i386_tss tss ss0
+
+expr I386_PGBYTES NBPG
+expr VM_MIN_ADDRESS
+expr VM_MAX_ADDRESS
+expr VM_MIN_KERNEL_ADDRESS KERNELBASE
+expr KERNEL_STACK_SIZE
+
+expr PDESHIFT
+expr PTESHIFT
+expr PTEMASK
+
+expr INTEL_PTE_PFN PTE_PFN
+expr INTEL_PTE_VALID PTE_V
+expr INTEL_PTE_WRITE PTE_W
+expr ~INTEL_PTE_VALID PTE_INVALID
+expr NPTES PTES_PER_PAGE
+expr INTEL_PTE_VALID|INTEL_PTE_WRITE INTEL_PTE_KERNEL
+
+expr IDTSZ
+expr GDTSZ
+expr LDTSZ
+
+expr KERNEL_CS
+expr KERNEL_DS
+expr KERNEL_TSS
+expr KERNEL_LDT
+
+expr (VM_MIN_KERNEL_ADDRESS>>PDESHIFT)*sizeof(pt_entry_t) KERNELBASEPDE
+
+#if MACH_KDB
+expr RB_KDB
+#endif MACH_KDB
+
+#if NCPUS > 1
+offset mp_desc_table mp gdt
+offset mp_desc_table mp idt
+#endif NCPUS > 1
+expr INTSTACK_SIZE
+
+#if !STAT_TIME
+offset timer tm low_bits LOW_BITS
+offset timer tm high_bits HIGH_BITS
+offset timer tm high_bits_check HIGH_BITS_CHECK
+expr TIMER_HIGH_UNIT
+offset thread th system_timer
+offset thread th user_timer
+#endif
+
diff --git a/i386/i386/idt-gen.h b/i386/i386/idt-gen.h
new file mode 100644
index 00000000..4663593e
--- /dev/null
+++ b/i386/i386/idt-gen.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+
+#ifndef _I386_IDT_
+#define _I386_IDT_
+
+#include <mach/vm_param.h>
+
+#include "seg.h"
+
+/*
+ * Interrupt table must always be at least 32 entries long,
+ * to cover the basic i386 exception vectors.
+ * More-specific code will probably define it to be longer,
+ * to allow separate entrypoints for hardware interrupts.
+ */
+#ifndef IDTSZ
+#error you need to define IDTSZ
+#endif
+
+extern struct real_gate idt[IDTSZ];
+
+/* Fill a gate in the IDT. */
+#define fill_idt_gate(int_num, entry, selector, access, dword_count) \
+ fill_gate(&idt[int_num], entry, selector, access, dword_count)
+
+#endif _I386_IDT_
diff --git a/i386/i386/idt.c b/i386/i386/idt.c
new file mode 100644
index 00000000..56688517
--- /dev/null
+++ b/i386/i386/idt.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+
+#include "vm_param.h"
+#include "seg.h"
+#include "idt.h"
+#include "gdt.h"
+
+struct real_gate idt[IDTSZ];
+
+struct idt_init_entry
+{
+ unsigned entrypoint;
+ unsigned short vector;
+ unsigned short type;
+};
+extern struct idt_init_entry idt_inittab[];
+
+void idt_init()
+{
+ struct idt_init_entry *iie = idt_inittab;
+
+ /* Initialize the exception vectors from the idt_inittab. */
+ while (iie->entrypoint)
+ {
+ fill_idt_gate(iie->vector, iie->entrypoint, KERNEL_CS, iie->type, 0);
+ iie++;
+ }
+
+ /* Load the IDT pointer into the processor. */
+ {
+ struct pseudo_descriptor pdesc;
+
+ pdesc.limit = sizeof(idt)-1;
+ pdesc.linear_base = kvtolin(&idt);
+ lidt(&pdesc);
+ }
+}
+
diff --git a/i386/i386/idt_inittab.S b/i386/i386/idt_inittab.S
new file mode 100644
index 00000000..77185681
--- /dev/null
+++ b/i386/i386/idt_inittab.S
@@ -0,0 +1,121 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+#include <mach/machine/asm.h>
+
+#include "seg.h"
+
+
+/* We'll be using macros to fill in a table in data hunk 2
+ while writing trap entrypoint routines at the same time.
+ Here's the header that comes before everything else. */
+ .data 2
+ENTRY(idt_inittab)
+ .text
+
+/*
+ * Interrupt descriptor table and code vectors for it.
+ */
+#define IDT_ENTRY(n,entry,type) \
+ .data 2 ;\
+ .long entry ;\
+ .word n ;\
+ .word type ;\
+ .text
+
+/*
+ * No error code. Clear error code and push trap number.
+ */
+#define EXCEPTION(n,name) \
+ IDT_ENTRY(n,EXT(name),ACC_PL_K|ACC_TRAP_GATE);\
+ENTRY(name) ;\
+ pushl $(0) ;\
+ pushl $(n) ;\
+ jmp EXT(alltraps)
+
+/*
+ * User-accessible exception. Otherwise, same as above.
+ */
+#define EXCEP_USR(n,name) \
+ IDT_ENTRY(n,EXT(name),ACC_PL_U|ACC_TRAP_GATE);\
+ENTRY(name) ;\
+ pushl $(0) ;\
+ pushl $(n) ;\
+ jmp EXT(alltraps)
+
+/*
+ * Error code has been pushed. Just push trap number.
+ */
+#define EXCEP_ERR(n,name) \
+ IDT_ENTRY(n,EXT(name),ACC_PL_K|ACC_INTR_GATE);\
+ENTRY(name) ;\
+ pushl $(n) ;\
+ jmp EXT(alltraps)
+
+/*
+ * Special interrupt code: dispatches to a unique entrypoint,
+ * not defined automatically here.
+ */
+#define EXCEP_SPC(n,name) \
+ IDT_ENTRY(n,EXT(name),ACC_PL_K|ACC_TRAP_GATE)
+
+
+EXCEPTION(0x00,t_zero_div)
+EXCEP_SPC(0x01,t_debug)
+/* skip NMI interrupt - let more specific code figure that out. */
+EXCEP_USR(0x03,t_int3)
+EXCEP_USR(0x04,t_into)
+EXCEP_USR(0x05,t_bounds)
+EXCEPTION(0x06,t_invop)
+EXCEPTION(0x07,t_nofpu)
+EXCEPTION(0x08,a_dbl_fault)
+EXCEPTION(0x09,a_fpu_over)
+EXCEPTION(0x0a,a_inv_tss)
+EXCEP_SPC(0x0b,t_segnp)
+EXCEP_ERR(0x0c,t_stack_fault)
+EXCEP_SPC(0x0d,t_gen_prot)
+EXCEP_SPC(0x0e,t_page_fault)
+EXCEPTION(0x0f,t_trap_0f)
+EXCEPTION(0x10,t_fpu_err)
+EXCEPTION(0x11,t_trap_11)
+EXCEPTION(0x12,t_trap_12)
+EXCEPTION(0x13,t_trap_13)
+EXCEPTION(0x14,t_trap_14)
+EXCEPTION(0x15,t_trap_15)
+EXCEPTION(0x16,t_trap_16)
+EXCEPTION(0x17,t_trap_17)
+EXCEPTION(0x18,t_trap_18)
+EXCEPTION(0x19,t_trap_19)
+EXCEPTION(0x1a,t_trap_1a)
+EXCEPTION(0x1b,t_trap_1b)
+EXCEPTION(0x1c,t_trap_1c)
+EXCEPTION(0x1d,t_trap_1d)
+EXCEPTION(0x1e,t_trap_1e)
+EXCEPTION(0x1f,t_trap_1f)
+
+/* Terminator */
+ .data 2
+ .long 0
+
diff --git a/i386/i386/io_emulate.c b/i386/i386/io_emulate.c
new file mode 100644
index 00000000..1bc5a75b
--- /dev/null
+++ b/i386/i386/io_emulate.c
@@ -0,0 +1,108 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+#include <platforms.h>
+
+#include <mach/boolean.h>
+#include <mach/port.h>
+#include <kern/thread.h>
+#include <kern/task.h>
+
+#include <ipc/ipc_port.h>
+#include <ipc/ipc_space.h>
+#include <ipc/ipc_right.h>
+#include <ipc/ipc_object.h>
+#include <ipc/ipc_entry.h>
+
+#include <device/dev_hdr.h>
+
+#include <i386/thread.h>
+#include <i386/io_port.h>
+#include <i386/io_emulate.h>
+
+extern ipc_port_t iopl_device_port;
+extern mach_device_t iopl_device;
+
+int
+emulate_io(regs, opcode, io_port)
+ struct i386_saved_state *regs;
+ int opcode;
+ int io_port;
+{
+ thread_t thread = current_thread();
+
+#if AT386
+ if (iopl_emulate(regs, opcode, io_port))
+ return EM_IO_DONE;
+#endif /* AT386 */
+
+ if (iopb_check_mapping(thread, iopl_device))
+ return EM_IO_ERROR;
+
+ /*
+ * Check for send rights to the IOPL device port.
+ */
+ if (iopl_device_port == IP_NULL)
+ return EM_IO_ERROR;
+ {
+ ipc_space_t space = current_space();
+ mach_port_t name;
+ ipc_entry_t entry;
+ boolean_t has_rights = FALSE;
+
+ is_write_lock(space);
+ assert(space->is_active);
+
+ if (ipc_right_reverse(space, (ipc_object_t) iopl_device_port,
+ &name, &entry)) {
+ /* iopl_device_port is locked and active */
+ if (entry->ie_bits & MACH_PORT_TYPE_SEND)
+ has_rights = TRUE;
+ ip_unlock(iopl_device_port);
+ }
+
+ is_write_unlock(space);
+ if (!has_rights) {
+ return EM_IO_ERROR;
+ }
+ }
+
+
+ /*
+ * Map the IOPL port set into the thread.
+ */
+
+ if (i386_io_port_add(thread, iopl_device)
+ != KERN_SUCCESS)
+ return EM_IO_ERROR;
+
+ /*
+ * Make the thread use its IO_TSS to get the IO permissions;
+ * it may not have had one before this.
+ */
+ switch_ktss(thread->pcb);
+
+ return EM_IO_RETRY;
+}
diff --git a/i386/i386/io_emulate.h b/i386/i386/io_emulate.h
new file mode 100644
index 00000000..de0d12df
--- /dev/null
+++ b/i386/i386/io_emulate.h
@@ -0,0 +1,43 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_IO_EMULATE_H_
+#define _I386_IO_EMULATE_H_
+
+/*
+ * Return codes from IO emulation.
+ */
+extern int emulate_io(/*
+ struct i386_saved_state *regs,
+ int opcode,
+ int io_port
+ */);
+
+#define EM_IO_DONE 0 /* IO instruction executed, proceed */
+#define EM_IO_RETRY 1 /* IO port mapped, retry instruction */
+#define EM_IO_ERROR 2 /* IO port not mapped */
+
+#endif /* _I386_IO_EMULATE_H_ */
diff --git a/i386/i386/io_map.c b/i386/i386/io_map.c
new file mode 100644
index 00000000..256a9a08
--- /dev/null
+++ b/i386/i386/io_map.c
@@ -0,0 +1,58 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <mach/vm_param.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_map.h>
+
+extern vm_offset_t kernel_virtual_start;
+
+/*
+ * Allocate and map memory for devices that may need to be mapped before
+ * Mach VM is running.
+ */
+vm_offset_t
+io_map(phys_addr, size)
+ vm_offset_t phys_addr;
+ vm_size_t size;
+{
+ vm_offset_t start;
+
+ if (kernel_map == VM_MAP_NULL) {
+ /*
+ * VM is not initialized. Grab memory.
+ */
+ start = kernel_virtual_start;
+ kernel_virtual_start += round_page(size);
+ printf("stealing kernel virtual addresses %08x-%08x\n", start, kernel_virtual_start);
+ }
+ else {
+ (void) kmem_alloc_pageable(kernel_map, &start, round_page(size));
+ }
+ (void) pmap_map_bd(start, phys_addr, phys_addr + round_page(size),
+ VM_PROT_READ|VM_PROT_WRITE);
+ return (start);
+}
diff --git a/i386/i386/io_port.h b/i386/i386/io_port.h
new file mode 100644
index 00000000..62022b78
--- /dev/null
+++ b/i386/i386/io_port.h
@@ -0,0 +1,43 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_IO_PORT_H_
+#define _I386_IO_PORT_H_
+/*
+ * IO register definitions.
+ */
+typedef unsigned short io_reg_t;
+
+#define IO_REG_NULL (0x00ff) /* reserved */
+
+/*
+ * Allocate and destroy io port sets for users to map into
+ * threads.
+ */
+extern void io_port_create(/* device_t, io_reg_t * */);
+extern void io_port_destroy(/* device_t */);
+
+#endif /* _I386_IO_PORT_H_ */
diff --git a/i386/i386/iopb.c b/i386/i386/iopb.c
new file mode 100644
index 00000000..d2addac0
--- /dev/null
+++ b/i386/i386/iopb.c
@@ -0,0 +1,615 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Code to manipulate IO permission bitmaps.
+ */
+
+#include <mach/boolean.h>
+#include <mach/kern_return.h>
+
+#include <ipc/ipc_port.h>
+
+#include <kern/kalloc.h>
+#include <kern/lock.h>
+#include <kern/queue.h>
+#include <kern/thread.h>
+
+#include <device/dev_hdr.h>
+
+#include "io_port.h"
+#include "iopb.h"
+#include "seg.h"
+#include "gdt.h"
+
+/*
+ * A set of ports for an IO device.
+ */
+struct io_port {
+ mach_device_t device; /* Mach device */
+ queue_chain_t dev_list; /* link in device list */
+ queue_chain_t io_use_list; /* List of threads that use it */
+ io_reg_t *io_port_list; /* list of IO ports that use it */
+ /* list ends with IO_REG_NULL */
+};
+typedef struct io_port *io_port_t;
+
+/*
+ * Lookup table for device -> io_port mapping
+ * (a linked list - I don't expect too many)
+ */
+queue_head_t device_to_io_port_list;
+
+/*
+ * Cross-reference:
+ * all threads that have IO ports mapped
+ * all IO ports that have threads mapped
+ */
+struct io_use {
+ queue_chain_t psq; /* Links from port set */
+ queue_chain_t tsq; /* links from tss */
+ io_port_t ps; /* Port set */
+ iopb_tss_t ts; /* Task segment */
+};
+typedef struct io_use *io_use_t;
+
+/*
+ * Big lock for the whole mess.
+ */
+decl_simple_lock_data(, iopb_lock)
+
+/*
+ * Initialize the package.
+ */
+void
+iopb_init(void)
+{
+ queue_init(&device_to_io_port_list);
+ simple_lock_init(&iopb_lock);
+}
+
+/*
+ * Initialize bitmap (set all bits to OFF == 1)
+ */
+void
+io_bitmap_init(
+ isa_iopb bp,
+ boolean_t on_off)
+{
+ register unsigned char *b = bp;
+ register int s;
+ unsigned char c;
+
+ /*
+ * Disallow access to ports 0x00 .. 0xff
+ */
+ for (s = 0; s < (0xff+1)/8; s++) {
+ *b++ = ~0; /* no access */
+ }
+
+ if (on_off)
+ c = 0;
+ else
+ c = ~0;
+
+ for (; s < sizeof(isa_iopb); s++) {
+ *b++ = c;
+ }
+}
+
+/*
+ * Set selected bits in bitmap to ON == 0
+ */
+void
+io_bitmap_set(
+ isa_iopb bp,
+ io_reg_t *bit_list)
+{
+ io_reg_t io_bit;
+
+ while ((io_bit = *bit_list++) != IO_REG_NULL) {
+ bp[io_bit>>3] &= ~(1 << (io_bit & 0x7));
+ }
+}
+
+/*
+ * Set selected bits in bitmap to OFF == 1
+ */
+void
+io_bitmap_clear(
+ isa_iopb bp,
+ io_reg_t *bit_list)
+{
+ io_reg_t io_bit;
+
+ while ((io_bit = *bit_list++) != IO_REG_NULL) {
+ bp[io_bit>>3] |= (1 << (io_bit & 0x7));
+ }
+}
+
+/*
+ * Lookup an io-port set by device
+ */
+io_port_t
+device_to_io_port_lookup(
+ mach_device_t device)
+{
+ register io_port_t io_port;
+
+ queue_iterate(&device_to_io_port_list, io_port, io_port_t, dev_list) {
+ if (io_port->device == device) {
+ return io_port;
+ }
+ }
+ return 0;
+}
+
+/*
+ * [exported]
+ * Create an io_port set
+ */
+void
+io_port_create(
+ mach_device_t device,
+ io_reg_t *io_port_list)
+{
+ register io_port_t io_port;
+
+ io_port = (io_port_t) kalloc(sizeof(struct io_port));
+
+ simple_lock(&iopb_lock);
+ if (device_to_io_port_lookup(device) != 0) {
+ simple_unlock(&iopb_lock);
+ kfree((vm_offset_t) io_port, sizeof(struct io_port));
+ return;
+ }
+
+ io_port->device = device;
+ queue_init(&io_port->io_use_list);
+ io_port->io_port_list = io_port_list;
+
+ /*
+ * Enter in lookup list.
+ */
+ queue_enter(&device_to_io_port_list, io_port, io_port_t, dev_list);
+
+ simple_unlock(&iopb_lock);
+}
+
+/*
+ * [exported]
+ * Destroy an io port set, removing any IO mappings.
+ */
+void
+io_port_destroy(
+ mach_device_t device)
+{
+ io_port_t io_port;
+ io_use_t iu;
+
+ simple_lock(&iopb_lock);
+ io_port = device_to_io_port_lookup(device);
+ if (io_port == 0) {
+ simple_unlock(&iopb_lock);
+ return;
+ }
+
+ queue_iterate(&io_port->io_use_list, iu, io_use_t, psq) {
+ iopb_tss_t io_tss;
+ io_tss = iu->ts;
+ io_bitmap_clear(io_tss->bitmap, io_port->io_port_list);
+ queue_remove(&io_tss->io_port_list, iu, io_use_t, tsq);
+ }
+ queue_remove(&device_to_io_port_list, io_port, io_port_t, dev_list);
+ simple_unlock(&iopb_lock);
+
+ while (!queue_empty(&io_port->io_use_list)) {
+ iu = (io_use_t) queue_first(&io_port->io_use_list);
+ queue_remove(&io_port->io_use_list, iu, io_use_t, psq);
+ kfree((vm_offset_t)iu, sizeof(struct io_use));
+ }
+
+ kfree((vm_offset_t)io_port, sizeof(struct io_port));
+}
+
+/*
+ * Initialize an IO TSS.
+ */
+void
+io_tss_init(
+ iopb_tss_t io_tss,
+ boolean_t access_all) /* allow access or not */
+{
+ vm_offset_t addr = (vm_offset_t) io_tss;
+ vm_size_t size = (char *)&io_tss->barrier - (char *)io_tss;
+
+ bzero(&io_tss->tss, sizeof(struct i386_tss));
+ io_tss->tss.io_bit_map_offset
+ = (char *)&io_tss->bitmap - (char *)io_tss;
+ io_tss->tss.ss0 = KERNEL_DS;
+ io_bitmap_init(io_tss->bitmap, access_all);
+ io_tss->barrier = ~0;
+ queue_init(&io_tss->io_port_list);
+ io_tss->iopb_desc[0] = ((size-1) & 0xffff)
+ | ((addr & 0xffff) << 16);
+ io_tss->iopb_desc[1] = ((addr & 0x00ff0000) >> 16)
+ | ((ACC_TSS|ACC_PL_K|ACC_P) << 8)
+ | ((size-1) & 0x000f0000)
+ | (addr & 0xff000000);
+}
+
+/*
+ * [exported]
+ * Create an IOPB_TSS
+ */
+iopb_tss_t
+iopb_create(void)
+{
+ register iopb_tss_t ts;
+
+ ts = (iopb_tss_t) kalloc(sizeof (struct iopb_tss));
+ io_tss_init(ts, TRUE); /* XXX */
+ return ts;
+}
+
+/*
+ * [exported]
+ * Destroy an IOPB_TSS
+ */
+void
+iopb_destroy(
+ iopb_tss_t io_tss)
+{
+ io_use_t iu;
+ io_port_t io_port;
+
+ simple_lock(&iopb_lock);
+
+ queue_iterate(&io_tss->io_port_list, iu, io_use_t, tsq) {
+ io_port = iu->ps;
+ /* skip bitmap clear - entire bitmap will vanish */
+ queue_remove(&io_port->io_use_list, iu, io_use_t, psq);
+ }
+
+ simple_unlock(&iopb_lock);
+
+ while (!queue_empty(&io_tss->io_port_list)) {
+ iu = (io_use_t) queue_first(&io_tss->io_port_list);
+ queue_remove(&io_tss->io_port_list, iu, io_use_t, tsq);
+ kfree((vm_offset_t)iu, sizeof(struct io_use));
+ }
+
+ kfree((vm_offset_t)io_tss, sizeof(struct iopb_tss));
+}
+
+/*
+ * Add an IO mapping to a thread.
+ */
+kern_return_t
+i386_io_port_add(
+ thread_t thread,
+ mach_device_t device)
+{
+ pcb_t pcb;
+ iopb_tss_t io_tss, new_io_tss;
+ io_port_t io_port;
+ io_use_t iu, old_iu;
+
+ if (thread == THREAD_NULL
+ || device == DEVICE_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ pcb = thread->pcb;
+
+ new_io_tss = 0;
+ iu = (io_use_t) kalloc(sizeof(struct io_use));
+
+ Retry:
+ simple_lock(&iopb_lock);
+
+ /* find the io_port_t for the device */
+ io_port = device_to_io_port_lookup(device);
+ if (io_port == 0) {
+ /*
+ * Device does not have IO ports available.
+ */
+ simple_unlock(&iopb_lock);
+ if (new_io_tss)
+ kfree((vm_offset_t)new_io_tss, sizeof(struct iopb_tss));
+ kfree((vm_offset_t) iu, sizeof(struct io_use));
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ /* Have the IO port. */
+
+ /* Make sure the thread has a TSS. */
+
+ simple_lock(&pcb->lock);
+ io_tss = pcb->ims.io_tss;
+ if (io_tss == 0) {
+ if (new_io_tss == 0) {
+ /*
+ * Allocate an IO-tss.
+ */
+ simple_unlock(&pcb->lock);
+ simple_unlock(&iopb_lock);
+
+ new_io_tss = (iopb_tss_t) kalloc(sizeof(struct iopb_tss));
+ io_tss_init(new_io_tss, TRUE); /* XXX */
+
+ goto Retry;
+ }
+ io_tss = new_io_tss;
+ pcb->ims.io_tss = io_tss;
+ new_io_tss = 0;
+ }
+
+ /*
+ * Have io_port and io_tss.
+ * See whether device is already mapped.
+ */
+ queue_iterate(&io_tss->io_port_list, old_iu, io_use_t, tsq) {
+ if (old_iu->ps == io_port) {
+ /*
+ * Already mapped.
+ */
+ simple_unlock(&pcb->lock);
+ simple_unlock(&iopb_lock);
+
+ kfree((vm_offset_t)iu, sizeof(struct io_use));
+ if (new_io_tss)
+ kfree((vm_offset_t)new_io_tss, sizeof(struct iopb_tss));
+ return KERN_SUCCESS;
+ }
+ }
+
+ /*
+ * Add mapping.
+ */
+ iu->ps = io_port;
+ iu->ts = io_tss;
+ queue_enter(&io_port->io_use_list, iu, io_use_t, psq);
+ queue_enter(&io_tss->io_port_list, iu, io_use_t, tsq);
+ io_bitmap_set(io_tss->bitmap, io_port->io_port_list);
+
+ simple_unlock(&pcb->lock);
+ simple_unlock(&iopb_lock);
+
+ if (new_io_tss)
+ kfree((vm_offset_t)new_io_tss, sizeof(struct iopb_tss));
+ return KERN_SUCCESS;
+
+}
+
+/*
+ * Remove an IO mapping from a thread.
+ */
+kern_return_t
+i386_io_port_remove(thread, device)
+ thread_t thread;
+ mach_device_t device;
+{
+ pcb_t pcb;
+ iopb_tss_t io_tss;
+ io_port_t io_port;
+ io_use_t iu;
+
+ if (thread == THREAD_NULL
+ || device == DEVICE_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ pcb = thread->pcb;
+
+ simple_lock(&iopb_lock);
+
+ /* find the io_port_t for the device */
+
+ io_port = device_to_io_port_lookup(device);
+ if (io_port == 0) {
+ /*
+ * Device does not have IO ports available.
+ */
+ simple_unlock(&iopb_lock);
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ simple_lock(&pcb->lock);
+ io_tss = pcb->ims.io_tss;
+ if (io_tss == 0) {
+ simple_unlock(&pcb->lock);
+ simple_unlock(&iopb_lock);
+ return KERN_INVALID_ARGUMENT; /* not mapped */
+ }
+
+ /*
+ * Find the mapping.
+ */
+ queue_iterate(&io_tss->io_port_list, iu, io_use_t, tsq) {
+ if (iu->ps == io_port) {
+ /*
+ * Found mapping. Remove it.
+ */
+ io_bitmap_clear(io_tss->bitmap, io_port->io_port_list);
+
+ queue_remove(&io_port->io_use_list, iu, io_use_t, psq);
+ queue_remove(&io_tss->io_port_list, iu, io_use_t, tsq);
+
+ simple_unlock(&pcb->lock);
+ simple_unlock(&iopb_lock);
+
+ kfree((vm_offset_t)iu, sizeof(struct io_use));
+
+ return KERN_SUCCESS;
+ }
+ }
+
+ /*
+ * No mapping.
+ */
+ return KERN_INVALID_ARGUMENT;
+}
+
+/*
+ * Return the IO ports mapped into a thread.
+ */
+extern ipc_port_t mach_convert_device_to_port(/* device_t */);
+
+kern_return_t
+i386_io_port_list(thread, list, list_count)
+ thread_t thread;
+ mach_device_t **list;
+ unsigned int *list_count;
+{
+ register pcb_t pcb;
+ register iopb_tss_t io_tss;
+ unsigned int count, alloc_count;
+ mach_device_t *devices;
+ vm_size_t size_needed, size;
+ vm_offset_t addr;
+ int i;
+
+ if (thread == THREAD_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ pcb = thread->pcb;
+
+ alloc_count = 16; /* a guess */
+
+ do {
+ size_needed = alloc_count * sizeof(ipc_port_t);
+ if (size_needed <= size)
+ break;
+
+ if (size != 0)
+ kfree(addr,size);
+
+ assert(size_needed > 0);
+ size = size_needed;
+
+ addr = kalloc(size);
+ if (addr == 0)
+ return KERN_RESOURCE_SHORTAGE;
+
+ devices = (mach_device_t *)addr;
+ count = 0;
+
+ simple_lock(&iopb_lock);
+ simple_lock(&pcb->lock);
+ io_tss = pcb->ims.io_tss;
+ if (io_tss != 0) {
+ register io_use_t iu;
+
+ queue_iterate(&io_tss->io_port_list, iu, io_use_t, tsq) {
+ if (++count < alloc_count) {
+ *devices = iu->ps->device;
+ device_reference(*devices);
+ devices++;
+ }
+ }
+ }
+ simple_unlock(&pcb->lock);
+ simple_unlock(&iopb_lock);
+ } while (count > alloc_count);
+
+ if (count == 0) {
+ /*
+ * No IO ports
+ */
+ *list = 0;
+ *list_count = 0;
+
+ if (size != 0)
+ kfree(addr, size);
+ }
+ else {
+ /*
+ * If we allocated too much, must copy.
+ */
+ size_needed = count * sizeof(ipc_port_t);
+ if (size_needed < size) {
+ vm_offset_t new_addr;
+
+ new_addr = kalloc(size_needed);
+ if (new_addr == 0) {
+ for (i = 0; i < count; i++)
+ device_deallocate(devices[i]);
+ kfree(addr, size);
+ return KERN_RESOURCE_SHORTAGE;
+ }
+
+ bcopy((void *)addr, (void *)new_addr, size_needed);
+ kfree(addr, size);
+ devices = (mach_device_t *)new_addr;
+ }
+
+ for (i = 0; i < count; i++)
+ ((ipc_port_t *)devices)[i] =
+ mach_convert_device_to_port(devices[i]);
+ }
+ *list = devices;
+ *list_count = count;
+
+ return KERN_SUCCESS;
+}
+
+/*
+ * Check whether an IO device is mapped to a particular thread.
+ * Used to support the 'iopl' device automatic mapping.
+ */
+boolean_t
+iopb_check_mapping(thread, device)
+ thread_t thread;
+ mach_device_t device;
+{
+ pcb_t pcb;
+ io_port_t io_port;
+ io_use_t iu;
+
+ pcb = thread->pcb;
+
+ simple_lock(&iopb_lock);
+
+ /* Find the io port for the device */
+
+ io_port = device_to_io_port_lookup(device);
+ if (io_port == 0) {
+ simple_unlock(&iopb_lock);
+ return FALSE;
+ }
+
+ /* Look up the mapping in the device`s mapping list. */
+
+ queue_iterate(&io_port->io_use_list, iu, io_use_t, psq) {
+ if (iu->ts == pcb->ims.io_tss) {
+ /*
+ * Device is mapped.
+ */
+ simple_unlock(&iopb_lock);
+ return TRUE;
+ }
+ }
+ simple_unlock(&iopb_lock);
+ return FALSE;
+}
diff --git a/i386/i386/iopb.h b/i386/i386/iopb.h
new file mode 100644
index 00000000..0a3e5745
--- /dev/null
+++ b/i386/i386/iopb.h
@@ -0,0 +1,62 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_IOPB_H_
+#define _I386_IOPB_H_
+
+#include <i386/tss.h>
+#include <kern/queue.h>
+
+/*
+ * IO permission bitmap.
+ *
+ * Allows only IO ports 0 .. 0x3ff: for ISA machines.
+ */
+
+#define iopb_howmany(a,b) (((a)+(b)-1)/(b))
+
+#define IOPB_MAX 0xffff /* ISA bus allows ports 0..3ff */
+ /* but accelerator cards are funky */
+#define IOPB_BYTES (iopb_howmany(IOPB_MAX+1,8))
+
+typedef unsigned char isa_iopb[IOPB_BYTES];
+
+/*
+ * An IO permission map is a task segment with an IO permission bitmap.
+ */
+
+struct iopb_tss {
+ struct i386_tss tss; /* task state segment */
+ isa_iopb bitmap; /* bitmap of mapped IO ports */
+ unsigned int barrier; /* bitmap barrier for CPU slop */
+ queue_head_t io_port_list; /* list of mapped IO ports */
+ int iopb_desc[2]; /* descriptor for this TSS */
+};
+
+typedef struct iopb_tss *iopb_tss_t;
+
+#endif /* _I386_IOPB_H_ */
+
diff --git a/i386/i386/ipl.h b/i386/i386/ipl.h
new file mode 100644
index 00000000..06ee58a0
--- /dev/null
+++ b/i386/i386/ipl.h
@@ -0,0 +1,77 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+Copyright (c) 1988,1989 Prime Computer, Inc. Natick, MA 01760
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this
+software and its documentation for any purpose and
+without fee is hereby granted, provided that the above
+copyright notice appears in all copies and that both the
+copyright notice and this permission notice appear in
+supporting documentation, and that the name of Prime
+Computer, Inc. not be used in advertising or publicity
+pertaining to distribution of the software without
+specific, written prior permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS", AND PRIME COMPUTER,
+INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN
+NO EVENT SHALL PRIME COMPUTER, INC. BE LIABLE FOR ANY
+SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN ACTION OF CONTRACT, NEGLIGENCE, OR
+OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+
+#define SPL0 0
+#define SPL1 1
+#define SPL2 2
+#define SPL3 3
+#define SPL4 4
+#define SPL5 5
+#define SPL6 6
+#define SPL7 7
+
+#define SPLPP 5
+#define SPLTTY 6
+#define SPLNI 6
+#define SPLHI 7
+#define IPLHI SPLHI
+
+#define NSPL (SPL7 + 1)
+
+#ifdef KERNEL
+#ifndef ASSEMBLER
+#include <machine/machspl.h>
+extern int (*ivect[])();
+extern int iunit[];
+extern int intpri[];
+#endif ASSEMBLER
+#endif KERNEL
diff --git a/i386/i386/ktss.c b/i386/i386/ktss.c
new file mode 100644
index 00000000..836a6f6c
--- /dev/null
+++ b/i386/i386/ktss.c
@@ -0,0 +1,61 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Kernel task state segment.
+ *
+ * We don't use the i386 task switch mechanism. We need a TSS
+ * only to hold the kernel stack pointer for the current thread.
+ *
+ * XXX multiprocessor??
+ */
+#include "vm_param.h"
+#include "seg.h"
+#include "gdt.h"
+#include "ktss.h"
+
+void
+ktss_init()
+{
+ /* XXX temporary exception stack */
+ static exception_stack[1024];
+
+ /* Initialize the master TSS descriptor. */
+ fill_gdt_descriptor(KERNEL_TSS,
+ kvtolin(&ktss), sizeof(ktss)+65536/8+1-1,
+ ACC_PL_K|ACC_TSS, 0);
+
+ /* Initialize the master TSS. */
+ ktss.ss0 = KERNEL_DS;
+ ktss.esp0 = (unsigned)(exception_stack+1024);
+ ktss.io_bit_map_offset = sizeof(ktss);
+
+ /* Set the last byte in the I/O bitmap to all 1's. */
+ ((unsigned char*)&ktss)[sizeof(ktss)+65536/8] = 0xff;
+
+ /* Load the TSS. */
+ ltr(KERNEL_TSS);
+}
+
diff --git a/i386/i386/ktss.h b/i386/i386/ktss.h
new file mode 100644
index 00000000..021f47fd
--- /dev/null
+++ b/i386/i386/ktss.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+#ifndef _I386_KTSS_
+#define _I386_KTSS_
+
+#include "tss.h"
+
+extern struct i386_tss ktss;
+
+#endif _I386_KTSS_
diff --git a/i386/i386/kttd_interface.c b/i386/i386/kttd_interface.c
new file mode 100644
index 00000000..3f2f3900
--- /dev/null
+++ b/i386/i386/kttd_interface.c
@@ -0,0 +1,577 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include "mach_ttd.h"
+
+#if MACH_TTD
+
+#include <mach/machine/eflags.h>
+
+#include <kern/thread.h>
+#include <kern/processor.h>
+#include <mach/thread_status.h>
+#include <mach/vm_param.h>
+#include <i386/seg.h>
+#include <sys/types.h>
+
+#include <ttd/ttd_types.h>
+#include <ttd/ttd_stub.h>
+#include <machine/kttd_machdep.h>
+
+/*
+ * Shamelessly copied from the ddb sources:
+ */
+struct i386_saved_state *kttd_last_saved_statep;
+struct i386_saved_state kttd_nested_saved_state;
+unsigned last_kttd_sp;
+
+struct i386_saved_state kttd_regs; /* was ddb_regs */
+
+extern int kttd_debug;
+extern boolean_t kttd_enabled;
+extern vm_offset_t virtual_end;
+
+#define I386_BREAKPOINT 0xcc
+
+/*
+ * kernel map
+ */
+extern vm_map_t kernel_map;
+
+boolean_t kttd_console_init(void)
+{
+ /*
+ * Get local machine's IP address via bootp.
+ */
+ return(ttd_ip_bootp());
+}
+
+/*
+ * Execute a break instruction that will invoke ttd
+ */
+void kttd_break(void)
+{
+ if (!kttd_enabled)
+ return;
+ asm("int3");
+}
+
+/*
+ * Halt all processors on the 386at (not really applicable).
+ */
+void kttd_halt_processors(void)
+{
+ /* XXX Fix for Sequent!!! */
+ /* Only one on AT386, so ignore for now... */
+}
+
+/*
+ * Determine whether or not the ehternet device driver supports
+ * ttd.
+ */
+boolean_t kttd_supported(void)
+{
+ return ((int)ttd_get_packet != NULL);
+}
+
+/*
+ * Return the ttd machine type for the i386at
+ */
+ttd_machine_type get_ttd_machine_type(void)
+{
+ return TTD_AT386;
+}
+
+void kttd_machine_getregs(struct i386_gdb_register_state *ttd_state)
+{
+ ttd_state->gs = kttd_regs.gs;
+ ttd_state->fs = kttd_regs.fs;
+ ttd_state->es = kttd_regs.es;
+ ttd_state->ds = kttd_regs.ds;
+ ttd_state->edi = kttd_regs.edi;
+ ttd_state->esi = kttd_regs.esi;
+ ttd_state->ebp = kttd_regs.ebp;
+
+ /*
+ * This is set up to point to the right place in
+ * kttd_trap and .
+ */
+ ttd_state->esp = kttd_regs.uesp;
+
+ ttd_state->ebx = kttd_regs.ebx;
+ ttd_state->edx = kttd_regs.edx;
+ ttd_state->ecx = kttd_regs.ecx;
+ ttd_state->eax = kttd_regs.eax;
+ ttd_state->eip = kttd_regs.eip;
+ ttd_state->cs = kttd_regs.cs;
+ ttd_state->efl = kttd_regs.efl;
+ ttd_state->ss = kttd_regs.ss;
+}
+
+void kttd_machine_setregs(struct i386_gdb_register_state *ttd_state)
+{
+ if (kttd_regs.gs != ttd_state->gs) {
+ if (kttd_debug)
+ printf("gs 0x%x:0x%x, ", kttd_regs.gs, ttd_state->gs);
+ kttd_regs.gs = ttd_state->gs;
+ }
+ if (kttd_regs.fs != ttd_state->fs) {
+ if (kttd_debug)
+ printf("fs 0x%x:0x%x, ", kttd_regs.fs, ttd_state->fs);
+ kttd_regs.fs = ttd_state->fs;
+ }
+ if (kttd_regs.es != ttd_state->es) {
+ if (kttd_debug)
+ printf("es 0x%x:0x%x, ", kttd_regs.es, ttd_state->es);
+ kttd_regs.es = ttd_state->es;
+ }
+ if (kttd_regs.ds != ttd_state->ds) {
+ if (kttd_debug)
+ printf("ds 0x%x:0x%x, ", kttd_regs.ds, ttd_state->ds);
+ kttd_regs.ds = ttd_state->ds;
+ }
+ if (kttd_regs.edi != ttd_state->edi) {
+ if (kttd_debug)
+ printf("edi 0x%x:0x%x, ", kttd_regs.edi, ttd_state->edi);
+ kttd_regs.edi = ttd_state->edi;
+ }
+ if (kttd_regs.esi != ttd_state->esi) {
+ if (kttd_debug)
+ printf("esi 0x%x:0x%x, ", kttd_regs.esi, ttd_state->esi);
+ kttd_regs.esi = ttd_state->esi;
+ }
+ if (kttd_regs.ebp != ttd_state->ebp) {
+ if (kttd_debug)
+ printf("ebp 0x%x:0x%x, ", kttd_regs.ebp, ttd_state->ebp);
+ kttd_regs.ebp = ttd_state->ebp;
+ }
+ if (kttd_regs.ebx != ttd_state->ebx) {
+ if (kttd_debug)
+ printf("ebx 0x%x:0x%x, ", kttd_regs.ebx, ttd_state->ebx);
+ kttd_regs.ebx = ttd_state->ebx;
+ }
+ if (kttd_regs.edx != ttd_state->edx) {
+ if (kttd_debug)
+ printf("edx 0x%x:0x%x, ", kttd_regs.edx, ttd_state->edx);
+ kttd_regs.edx = ttd_state->edx;
+ }
+ if (kttd_regs.ecx != ttd_state->ecx) {
+ if (kttd_debug)
+ printf("ecx 0x%x:0x%x, ", kttd_regs.ecx, ttd_state->ecx);
+ kttd_regs.ecx = ttd_state->ecx;
+ }
+ if (kttd_regs.eax != ttd_state->eax) {
+ if (kttd_debug)
+ printf("eax 0x%x:0x%x, ", kttd_regs.eax, ttd_state->eax);
+ kttd_regs.eax = ttd_state->eax;
+ }
+ if (kttd_regs.eip != ttd_state->eip) {
+ if (kttd_debug)
+ printf("eip 0x%x:0x%x, ", kttd_regs.eip, ttd_state->eip);
+ kttd_regs.eip = ttd_state->eip;
+ }
+ if (kttd_regs.cs != ttd_state->cs) {
+ if (kttd_debug)
+ printf("cs 0x%x:0x%x, ", kttd_regs.cs, ttd_state->cs);
+ kttd_regs.cs = ttd_state->cs;
+ }
+ if (kttd_regs.efl != ttd_state->efl) {
+ if (kttd_debug)
+ printf("efl 0x%x:0x%x, ", kttd_regs.efl, ttd_state->efl);
+ kttd_regs.efl = ttd_state->efl;
+ }
+#if 0
+ /*
+ * We probably shouldn't mess with the uesp or the ss? XXX
+ */
+ if (kttd_regs.ss != ttd_state->ss) {
+ if (kttd_debug)
+ printf("ss 0x%x:0x%x, ", kttd_regs.ss, ttd_state->ss);
+ kttd_regs.ss = ttd_state->ss;
+ }
+#endif 0
+
+}
+
+/*
+ * Enable a page for access, faulting it in if necessary
+ */
+boolean_t kttd_mem_access(vm_offset_t offset, vm_prot_t access)
+{
+ kern_return_t code;
+
+ /*
+ * VM_MIN_KERNEL_ADDRESS if the beginning of equiv
+ * mapped kernel memory. virtual_end is the end.
+ * If it's in between it's always accessible
+ */
+ if (offset >= VM_MIN_KERNEL_ADDRESS && offset < virtual_end)
+ return TRUE;
+
+ if (offset >= virtual_end) {
+ /*
+ * fault in the memory just to make sure we can access it
+ */
+ if (kttd_debug)
+ printf(">>>>>>>>>>Faulting in memory: 0x%x, 0x%x\n",
+ trunc_page(offset), access);
+ code = vm_fault(kernel_map, trunc_page(offset), access, FALSE,
+ FALSE, (void (*)()) 0);
+ }else{
+ /*
+ * Check for user thread
+ */
+#if 1
+ if ((current_thread() != THREAD_NULL) &&
+ (current_thread()->task->map->pmap != kernel_pmap) &&
+ (current_thread()->task->map->pmap != PMAP_NULL)) {
+ code = vm_fault(current_thread()->task->map,
+ trunc_page(offset), access, FALSE,
+ FALSE, (void (*)()) 0);
+ }else{
+ /*
+ * Invalid kernel address (below VM_MIN_KERNEL_ADDRESS)
+ */
+ return FALSE;
+ }
+#else
+ if (kttd_debug)
+ printf("==========Would've tried to map in user area 0x%x\n",
+ trunc_page(offset));
+ return FALSE;
+#endif /* 0 */
+ }
+
+ return (code == KERN_SUCCESS);
+}
+
+/*
+ * See if we modified the kernel text and if so flush the caches.
+ * This routine is never called with a range that crosses a page
+ * boundary.
+ */
+void kttd_flush_cache(vm_offset_t offset, vm_size_t length)
+{
+ /* 386 doesn't need this */
+ return;
+}
+
+/*
+ * Insert a breakpoint into memory.
+ */
+boolean_t kttd_insert_breakpoint(vm_address_t address,
+ ttd_saved_inst *saved_inst)
+{
+ /*
+ * Saved old memory data:
+ */
+ *saved_inst = *(unsigned char *)address;
+
+ /*
+ * Put in a Breakpoint:
+ */
+ *(unsigned char *)address = I386_BREAKPOINT;
+
+ return TRUE;
+}
+
+/*
+ * Remove breakpoint from memory.
+ */
+boolean_t kttd_remove_breakpoint(vm_address_t address,
+ ttd_saved_inst saved_inst)
+{
+ /*
+ * replace it:
+ */
+ *(unsigned char *)address = (saved_inst & 0xff);
+
+ return TRUE;
+}
+
+/*
+ * Set single stepping mode. Assumes that program counter is set
+ * to the location where single stepping is to begin. The 386 is
+ * an easy single stepping machine, ie. built into the processor.
+ */
+boolean_t kttd_set_machine_single_step(void)
+{
+ /* Turn on Single Stepping */
+ kttd_regs.efl |= EFL_TF;
+
+ return TRUE;
+}
+
+/*
+ * Clear single stepping mode.
+ */
+boolean_t kttd_clear_machine_single_step(void)
+{
+ /* Turn off the trace flag */
+ kttd_regs.efl &= ~EFL_TF;
+
+ return TRUE;
+}
+
+
+/*
+ * kttd_type_to_ttdtrap:
+ *
+ * Fills in the task and thread info structures with the reason
+ * for entering the Teledebugger (bp, single step, pg flt, etc.)
+ *
+ */
+void kttd_type_to_ttdtrap(int type)
+{
+ /* XXX Fill this in sometime for i386 */
+}
+
+/*
+ * kttd_trap:
+ *
+ * This routine is called from the trap or interrupt handler when a
+ * breakpoint instruction is encountered or a single step operation
+ * completes. The argument is a pointer to a machine dependent
+ * saved_state structure that was built on the interrupt or kernel stack.
+ *
+ */
+boolean_t kttd_trap(int type, int code, struct i386_saved_state *regs)
+{
+ int s;
+
+ if (kttd_debug)
+ printf("kttd_TRAP, before splhigh()\n");
+
+ /*
+ * TTD isn't supported by the driver.
+ *
+ * Try to switch off to kdb if it is resident.
+ * Otherwise just hang (this might be panic).
+ *
+ * Check to make sure that TTD is supported.
+ * (Both by the machine's driver's, and bootp if using ether).
+ */
+ if (!kttd_supported()) {
+ kttd_enabled = FALSE;
+ return FALSE;
+ }
+
+ s = splhigh();
+
+ /*
+ * We are already in TTD!
+ */
+ if (++kttd_active > MAX_KTTD_ACTIVE) {
+ printf("kttd_trap: RE-ENTERED!!!\n");
+ }
+
+ if (kttd_debug)
+ printf("kttd_TRAP, after splhigh()\n");
+
+ /* Should switch to kttd's own stack here. */
+
+ kttd_regs = *regs;
+
+ if ((regs->cs & 0x3) == 0) {
+ /*
+ * Kernel mode - esp and ss not saved
+ */
+ kttd_regs.uesp = (int)&regs->uesp; /* kernel stack pointer */
+ kttd_regs.ss = KERNEL_DS;
+ }
+
+ /*
+ * If this was not entered via an interrupt (type != -1)
+ * then we've entered via a bpt, single, etc. and must
+ * set the globals.
+ *
+ * Setup the kttd globals for entry....
+ */
+ if (type != -1) {
+ kttd_current_request = NULL;
+ kttd_current_length = 0;
+ kttd_current_kmsg = NULL;
+ kttd_run_status = FULL_STOP;
+ }else{
+ /*
+ * We know that we can only get here if we did a kttd_intr
+ * since it's the way that we are called with type -1 (via
+ * the trampoline), so we don't have to worry about entering
+ * from Cntl-Alt-D like the mips does.
+ */
+ /*
+ * Perform sanity check!
+ */
+ if ((kttd_current_request == NULL) ||
+ (kttd_current_length == 0) ||
+ (kttd_current_kmsg == NULL) ||
+ (kttd_run_status != ONE_STOP)) {
+
+ printf("kttd_trap: INSANITY!!!\n");
+ }
+ }
+
+ kttd_task_trap(type, code, (regs->cs & 0x3) != 0);
+
+ regs->eip = kttd_regs.eip;
+ regs->efl = kttd_regs.efl;
+ regs->eax = kttd_regs.eax;
+ regs->ecx = kttd_regs.ecx;
+ regs->edx = kttd_regs.edx;
+ regs->ebx = kttd_regs.ebx;
+ if (regs->cs & 0x3) {
+ /*
+ * user mode - saved esp and ss valid
+ */
+ regs->uesp = kttd_regs.uesp; /* user stack pointer */
+ regs->ss = kttd_regs.ss & 0xffff; /* user stack segment */
+ }
+ regs->ebp = kttd_regs.ebp;
+ regs->esi = kttd_regs.esi;
+ regs->edi = kttd_regs.edi;
+ regs->es = kttd_regs.es & 0xffff;
+ regs->cs = kttd_regs.cs & 0xffff;
+ regs->ds = kttd_regs.ds & 0xffff;
+ regs->fs = kttd_regs.fs & 0xffff;
+ regs->gs = kttd_regs.gs & 0xffff;
+
+ if (--kttd_active < MIN_KTTD_ACTIVE)
+ printf("ttd_trap: kttd_active < 0\n");
+
+ if (kttd_debug) {
+ printf("Leaving kttd_trap, kttd_active = %d\n", kttd_active);
+ }
+
+ /*
+ * Only reset this if we entered kttd_trap via an async trampoline.
+ */
+ if (type == -1) {
+ if (kttd_run_status == RUNNING)
+ printf("kttd_trap: $$$$$ run_status already RUNNING! $$$$$\n");
+ kttd_run_status = RUNNING;
+ }
+
+ /* Is this right? XXX */
+ kttd_run_status = RUNNING;
+
+ (void) splx(s);
+
+ /*
+ * Return true, that yes we handled the trap.
+ */
+ return TRUE;
+}
+
+/*
+ * Enter KTTD through a network packet trap.
+ * We show the registers as of the network interrupt
+ * instead of those at its call to KDB.
+ */
+struct int_regs {
+ int gs;
+ int fs;
+ int edi;
+ int esi;
+ int ebp;
+ int ebx;
+ struct i386_interrupt_state *is;
+};
+
+void
+kttd_netentry(int_regs)
+ struct int_regs *int_regs;
+{
+ struct i386_interrupt_state *is = int_regs->is;
+ int s;
+
+ if (kttd_debug)
+ printf("kttd_NETENTRY before slphigh()\n");
+
+ s = splhigh();
+
+ if (kttd_debug)
+ printf("kttd_NETENTRY after slphigh()\n");
+
+ if (is->cs & 0x3) {
+ /*
+ * Interrupted from User Space
+ */
+ kttd_regs.uesp = ((int *)(is+1))[0];
+ kttd_regs.ss = ((int *)(is+1))[1];
+ }
+ else {
+ /*
+ * Interrupted from Kernel Space
+ */
+ kttd_regs.ss = KERNEL_DS;
+ kttd_regs.uesp= (int)(is+1);
+ }
+ kttd_regs.efl = is->efl;
+ kttd_regs.cs = is->cs;
+ kttd_regs.eip = is->eip;
+ kttd_regs.eax = is->eax;
+ kttd_regs.ecx = is->ecx;
+ kttd_regs.edx = is->edx;
+ kttd_regs.ebx = int_regs->ebx;
+ kttd_regs.ebp = int_regs->ebp;
+ kttd_regs.esi = int_regs->esi;
+ kttd_regs.edi = int_regs->edi;
+ kttd_regs.ds = is->ds;
+ kttd_regs.es = is->es;
+ kttd_regs.fs = int_regs->fs;
+ kttd_regs.gs = int_regs->gs;
+
+ kttd_active++;
+ kttd_task_trap(-1, 0, (kttd_regs.cs & 0x3) != 0);
+ kttd_active--;
+
+ if (kttd_regs.cs & 0x3) {
+ ((int *)(is+1))[0] = kttd_regs.uesp;
+ ((int *)(is+1))[1] = kttd_regs.ss & 0xffff;
+ }
+ is->efl = kttd_regs.efl;
+ is->cs = kttd_regs.cs & 0xffff;
+ is->eip = kttd_regs.eip;
+ is->eax = kttd_regs.eax;
+ is->ecx = kttd_regs.ecx;
+ is->edx = kttd_regs.edx;
+ int_regs->ebx = kttd_regs.ebx;
+ int_regs->ebp = kttd_regs.ebp;
+ int_regs->esi = kttd_regs.esi;
+ int_regs->edi = kttd_regs.edi;
+ is->ds = kttd_regs.ds & 0xffff;
+ is->es = kttd_regs.es & 0xffff;
+ int_regs->fs = kttd_regs.fs & 0xffff;
+ int_regs->gs = kttd_regs.gs & 0xffff;
+
+ if (kttd_run_status == RUNNING)
+ printf("kttd_netentry: %%%%% run_status already RUNNING! %%%%%\n");
+ kttd_run_status = RUNNING;
+
+ (void) splx(s);
+}
+
+#endif MACH_TTD
diff --git a/i386/i386/kttd_machdep.h b/i386/i386/kttd_machdep.h
new file mode 100644
index 00000000..8ac7de18
--- /dev/null
+++ b/i386/i386/kttd_machdep.h
@@ -0,0 +1,59 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _KTTD_MACHDEP_H_
+#define _KTTD_MACHDEP_H_
+
+#define MAX_KTTD_ACTIVE 2
+#define MIN_KTTD_ACTIVE 0
+
+/*
+ * Register state for gdb
+ */
+struct i386_gdb_register_state {
+ int eax;
+ int ecx;
+ int edx;
+ int ebx;
+ int esp; /* 4 */
+ int ebp; /* 5 */
+ int esi;
+ int edi;
+ int eip; /* 8 */
+ int efl; /* 9 */
+ int cs;
+ int ss;
+ int ds;
+ int es;
+ int fs;
+ int gs;
+};
+
+typedef struct i386_gdb_register_state ttd_machine_state;
+
+typedef unsigned long ttd_saved_inst;
+
+#endif /* _KTTD_MACHDEP_H_ */
diff --git a/i386/i386/ldt.c b/i386/i386/ldt.c
new file mode 100644
index 00000000..a2b125ce
--- /dev/null
+++ b/i386/i386/ldt.c
@@ -0,0 +1,64 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * "Local" descriptor table. At the moment, all tasks use the
+ * same LDT.
+ */
+#include <mach/machine/vm_types.h>
+
+#include "vm_param.h"
+#include "seg.h"
+#include "gdt.h"
+#include "ldt.h"
+
+extern int syscall();
+
+struct real_descriptor ldt[LDTSZ];
+
+void
+ldt_init()
+{
+ /* Initialize the master LDT descriptor in the GDT. */
+ fill_gdt_descriptor(KERNEL_LDT,
+ kvtolin(&ldt), sizeof(ldt)-1,
+ ACC_PL_K|ACC_LDT, 0);
+
+ /* Initialize the LDT descriptors. */
+ fill_ldt_gate(USER_SCALL,
+ (vm_offset_t)&syscall, KERNEL_CS,
+ ACC_PL_U|ACC_CALL_GATE, 0);
+ fill_ldt_descriptor(USER_CS,
+ VM_MIN_ADDRESS, VM_MAX_ADDRESS-VM_MIN_ADDRESS,
+ /* XXX LINEAR_... */
+ ACC_PL_U|ACC_CODE_R, SZ_32);
+ fill_ldt_descriptor(USER_DS,
+ VM_MIN_ADDRESS, VM_MAX_ADDRESS-VM_MIN_ADDRESS,
+ ACC_PL_U|ACC_DATA_W, SZ_32);
+
+ /* Activate the LDT. */
+ lldt(KERNEL_LDT);
+}
+
diff --git a/i386/i386/ldt.h b/i386/i386/ldt.h
new file mode 100644
index 00000000..da0b0af3
--- /dev/null
+++ b/i386/i386/ldt.h
@@ -0,0 +1,66 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * Copyright (c) 1991 IBM Corporation
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory (CSL).
+ * 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,
+ * and that the name IBM not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written
+ * prior permission.
+ *
+ * CARNEGIE MELLON, IBM, AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON, IBM, AND CSL DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * This file describes the standard LDT provided by default
+ * to all user-level Mach tasks.
+ */
+#ifndef _I386_LDT_
+#define _I386_LDT_
+
+#include "seg.h"
+
+/*
+ * User descriptors for Mach - 32-bit flat address space
+ */
+#define USER_SCALL 0x07 /* system call gate */
+#define USER_CS 0x17 /* user code segment */
+#define USER_DS 0x1f /* user data segment */
+
+#define LDTSZ 4
+
+
+#ifndef ASSEMBLER
+
+extern struct real_descriptor ldt[LDTSZ];
+
+/* Fill a segment descriptor in the LDT. */
+#define fill_ldt_descriptor(selector, base, limit, access, sizebits) \
+ fill_descriptor(&ldt[selector/8], base, limit, access, sizebits)
+
+#define fill_ldt_gate(selector, offset, dest_selector, access, word_count) \
+ fill_gate((struct real_gate*)&ldt[selector/8], \
+ offset, dest_selector, access, word_count)
+
+#endif !ASSEMBLER
+
+#endif _I386_LDT_
diff --git a/i386/i386/lock.h b/i386/i386/lock.h
new file mode 100644
index 00000000..053a3ea6
--- /dev/null
+++ b/i386/i386/lock.h
@@ -0,0 +1,130 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Machine-dependent simple locks for the i386.
+ */
+#ifndef _I386_LOCK_H_
+#define _I386_LOCK_H_
+
+#if NCPUS > 1
+
+/*
+ * All of the locking routines are built from calls on
+ * a locked-exchange operation. Values of the lock are
+ * 0 for unlocked, 1 for locked.
+ */
+
+#ifdef __GNUC__
+
+/*
+ * The code here depends on the GNU C compiler.
+ */
+
+#define _simple_lock_xchg_(lock, new_val) \
+ ({ register int _old_val_; \
+ asm volatile("xchgl %0, %2" \
+ : "=r" (_old_val_) \
+ : "0" (new_val), "m" (*(lock)) \
+ ); \
+ _old_val_; \
+ })
+
+#define simple_lock_init(l) \
+ ((l)->lock_data = 0)
+
+#define simple_lock(l) \
+ ({ \
+ while(_simple_lock_xchg_(l, 1)) \
+ while (*(volatile int *)&(l)->lock_data) \
+ continue; \
+ 0; \
+ })
+
+#define simple_unlock(l) \
+ (_simple_lock_xchg_(l, 0))
+
+#define simple_lock_try(l) \
+ (!_simple_lock_xchg_(l, 1))
+
+/*
+ * General bit-lock routines.
+ */
+#define bit_lock(bit, l) \
+ ({ \
+ asm volatile(" jmp 1f \n\
+ 0: btl %0, %1 \n\
+ jb 0b \n\
+ 1: lock \n\
+ btsl %0, %1 \n\
+ jb 0b" \
+ : \
+ : "r" (bit), "m" (*(volatile int *)(l))); \
+ 0; \
+ })
+
+#define bit_unlock(bit, l) \
+ ({ \
+ asm volatile(" lock \n\
+ btrl %0, %1" \
+ : \
+ : "r" (bit), "m" (*(volatile int *)(l))); \
+ 0; \
+ })
+
+/*
+ * Set or clear individual bits in a long word.
+ * The locked access is needed only to lock access
+ * to the word, not to individual bits.
+ */
+#define i_bit_set(bit, l) \
+ ({ \
+ asm volatile(" lock \n\
+ btsl %0, %1" \
+ : \
+ : "r" (bit), "m" (*(l)) ); \
+ 0; \
+ })
+
+#define i_bit_clear(bit, l) \
+ ({ \
+ asm volatile(" lock \n\
+ btrl %0, %1" \
+ : \
+ : "r" (bit), "m" (*(l)) ); \
+ 0; \
+ })
+
+#endif /* __GNUC__ */
+
+extern void simple_lock_pause();
+
+#endif NCPUS > 1
+
+
+#include_next "lock.h"
+
+
+#endif /* _I386_LOCK_H_ */
diff --git a/i386/i386/locore.S b/i386/i386/locore.S
new file mode 100644
index 00000000..8bc5d5e0
--- /dev/null
+++ b/i386/i386/locore.S
@@ -0,0 +1,1726 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
+ * Copyright (c) 1991 IBM Corporation
+ * 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,
+ * and that the nema IBM not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written
+ * prior permission.
+ *
+ * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <cpus.h>
+#include <platforms.h>
+#include <mach_kdb.h>
+#include <mach_ttd.h>
+#include <stat_time.h>
+
+#include <mach/machine/asm.h>
+#include <mach/machine/eflags.h>
+#include "proc_reg.h"
+#include "trap.h"
+#include "seg.h"
+#include "ldt.h"
+#include "i386asm.h"
+#include "cpu_number.h"
+
+/*
+ * Fault recovery.
+ */
+#define RECOVER_TABLE_START \
+ .text 2 ;\
+DATA(recover_table) ;\
+ .text
+
+#define RECOVER(addr) \
+ .text 2 ;\
+ .long 9f ;\
+ .long addr ;\
+ .text ;\
+9:
+
+#define RECOVER_TABLE_END \
+ .text 2 ;\
+ .globl EXT(recover_table_end) ;\
+LEXT(recover_table_end) ;\
+ .text
+
+/*
+ * Retry table for certain successful faults.
+ */
+#define RETRY_TABLE_START \
+ .text 3 ;\
+DATA(retry_table) ;\
+ .text
+
+#define RETRY(addr) \
+ .text 3 ;\
+ .long 9f ;\
+ .long addr ;\
+ .text ;\
+9:
+
+#define RETRY_TABLE_END \
+ .text 3 ;\
+ .globl EXT(retry_table_end) ;\
+LEXT(retry_table_end) ;\
+ .text
+
+/*
+ * Allocate recovery and retry tables.
+ */
+ RECOVER_TABLE_START
+ RETRY_TABLE_START
+
+/*
+ * Timing routines.
+ */
+#if STAT_TIME
+
+#define TIME_TRAP_UENTRY
+#define TIME_TRAP_SENTRY
+#define TIME_TRAP_UEXIT
+#define TIME_INT_ENTRY
+#define TIME_INT_EXIT
+
+#else /* microsecond timing */
+
+/*
+ * Microsecond timing.
+ * Assumes a free-running microsecond counter.
+ * no TIMER_MAX check needed.
+ */
+
+/*
+ * There is only one current time-stamp per CPU, since only
+ * the time-stamp in the current timer is used.
+ * To save time, we allocate the current time-stamps here.
+ */
+ .comm _current_tstamp, 4*NCPUS
+
+/*
+ * Update time on user trap entry.
+ * 11 instructions (including cli on entry)
+ * Assumes CPU number in %edx.
+ * Uses %eax, %ebx, %ecx.
+ */
+#define TIME_TRAP_UENTRY \
+ cli /* block interrupts */ ;\
+ movl VA_ETC,%ebx /* get timer value */ ;\
+ movl CX(_current_tstamp,%edx),%ecx /* get old time stamp */;\
+ movl %ebx,CX(_current_tstamp,%edx) /* set new time stamp */;\
+ subl %ecx,%ebx /* elapsed = new-old */ ;\
+ movl CX(_current_timer,%edx),%ecx /* get current timer */ ;\
+ addl %ebx,LOW_BITS(%ecx) /* add to low bits */ ;\
+ jns 0f /* if overflow, */ ;\
+ call timer_normalize /* normalize timer */ ;\
+0: addl $(TH_SYS_TIMER-TH_USER_TIMER),%ecx ;\
+ /* switch to sys timer */;\
+ movl %ecx,CX(_current_timer,%edx) /* make it current */ ;\
+ sti /* allow interrupts */
+
+/*
+ * Update time on system call entry.
+ * 11 instructions (including cli on entry)
+ * Assumes CPU number in %edx.
+ * Uses %ebx, %ecx.
+ * Same as TIME_TRAP_UENTRY, but preserves %eax.
+ */
+#define TIME_TRAP_SENTRY \
+ cli /* block interrupts */ ;\
+ movl VA_ETC,%ebx /* get timer value */ ;\
+ movl CX(_current_tstamp,%edx),%ecx /* get old time stamp */;\
+ movl %ebx,CX(_current_tstamp,%edx) /* set new time stamp */;\
+ subl %ecx,%ebx /* elapsed = new-old */ ;\
+ movl CX(_current_timer,%edx),%ecx /* get current timer */ ;\
+ addl %ebx,LOW_BITS(%ecx) /* add to low bits */ ;\
+ jns 0f /* if overflow, */ ;\
+ pushl %eax /* save %eax */ ;\
+ call timer_normalize /* normalize timer */ ;\
+ popl %eax /* restore %eax */ ;\
+0: addl $(TH_SYS_TIMER-TH_USER_TIMER),%ecx ;\
+ /* switch to sys timer */;\
+ movl %ecx,CX(_current_timer,%edx) /* make it current */ ;\
+ sti /* allow interrupts */
+
+/*
+ * update time on user trap exit.
+ * 10 instructions.
+ * Assumes CPU number in %edx.
+ * Uses %ebx, %ecx.
+ */
+#define TIME_TRAP_UEXIT \
+ cli /* block interrupts */ ;\
+ movl VA_ETC,%ebx /* get timer */ ;\
+ movl CX(_current_tstamp,%edx),%ecx /* get old time stamp */;\
+ movl %ebx,CX(_current_tstamp,%edx) /* set new time stamp */;\
+ subl %ecx,%ebx /* elapsed = new-old */ ;\
+ movl CX(_current_timer,%edx),%ecx /* get current timer */ ;\
+ addl %ebx,LOW_BITS(%ecx) /* add to low bits */ ;\
+ jns 0f /* if overflow, */ ;\
+ call timer_normalize /* normalize timer */ ;\
+0: addl $(TH_USER_TIMER-TH_SYS_TIMER),%ecx ;\
+ /* switch to user timer */;\
+ movl %ecx,CX(_current_timer,%edx) /* make it current */
+
+/*
+ * update time on interrupt entry.
+ * 9 instructions.
+ * Assumes CPU number in %edx.
+ * Leaves old timer in %ebx.
+ * Uses %ecx.
+ */
+#define TIME_INT_ENTRY \
+ movl VA_ETC,%ecx /* get timer */ ;\
+ movl CX(_current_tstamp,%edx),%ebx /* get old time stamp */;\
+ movl %ecx,CX(_current_tstamp,%edx) /* set new time stamp */;\
+ subl %ebx,%ecx /* elapsed = new-old */ ;\
+ movl CX(_current_timer,%edx),%ebx /* get current timer */ ;\
+ addl %ecx,LOW_BITS(%ebx) /* add to low bits */ ;\
+ leal CX(0,%edx),%ecx /* timer is 16 bytes */ ;\
+ lea CX(_kernel_timer,%edx),%ecx /* get interrupt timer*/;\
+ movl %ecx,CX(_current_timer,%edx) /* set timer
+
+/*
+ * update time on interrupt exit.
+ * 11 instructions
+ * Assumes CPU number in %edx, old timer in %ebx.
+ * Uses %eax, %ecx.
+ */
+#define TIME_INT_EXIT \
+ movl VA_ETC,%eax /* get timer */ ;\
+ movl CX(_current_tstamp,%edx),%ecx /* get old time stamp */;\
+ movl %eax,CX(_current_tstamp,%edx) /* set new time stamp */;\
+ subl %ecx,%eax /* elapsed = new-old */ ;\
+ movl CX(_current_timer,%edx),%ecx /* get current timer */ ;\
+ addl %eax,LOW_BITS(%ecx) /* add to low bits */ ;\
+ jns 0f /* if overflow, */ ;\
+ call timer_normalize /* normalize timer */ ;\
+0: testb $0x80,LOW_BITS+3(%ebx) /* old timer overflow? */;\
+ jz 0f /* if overflow, */ ;\
+ movl %ebx,%ecx /* get old timer */ ;\
+ call timer_normalize /* normalize timer */ ;\
+0: movl %ebx,CX(_current_timer,%edx) /* set timer */
+
+
+/*
+ * Normalize timer in ecx.
+ * Preserves edx; clobbers eax.
+ */
+ .align 2
+timer_high_unit:
+ .long TIMER_HIGH_UNIT /* div has no immediate opnd */
+
+timer_normalize:
+ pushl %edx /* save register */
+ xorl %edx,%edx /* clear divisor high */
+ movl LOW_BITS(%ecx),%eax /* get divisor low */
+ divl timer_high_unit,%eax /* quotient in eax */
+ /* remainder in edx */
+ addl %eax,HIGH_BITS_CHECK(%ecx) /* add high_inc to check */
+ movl %edx,LOW_BITS(%ecx) /* remainder to low_bits */
+ addl %eax,HIGH_BITS(%ecx) /* add high_inc to high bits */
+ popl %edx /* restore register */
+ ret
+
+/*
+ * Switch to a new timer.
+ */
+ENTRY(timer_switch)
+ CPU_NUMBER(%edx) /* get this CPU */
+ movl VA_ETC,%ecx /* get timer */
+ movl CX(_current_tstamp,%edx),%eax /* get old time stamp */
+ movl %ecx,CX(_current_tstamp,%edx) /* set new time stamp */
+ subl %ecx,%eax /* elapsed = new - old */
+ movl CX(_current_timer,%edx),%ecx /* get current timer */
+ addl %eax,LOW_BITS(%ecx) /* add to low bits */
+ jns 0f /* if overflow, */
+ call timer_normalize /* normalize timer */
+0:
+ movl S_ARG0,%ecx /* get new timer */
+ movl %ecx,CX(_current_timer,%edx) /* set timer */
+ ret
+
+/*
+ * Initialize the first timer for a CPU.
+ */
+ENTRY(start_timer)
+ CPU_NUMBER(%edx) /* get this CPU */
+ movl VA_ETC,%ecx /* get timer */
+ movl %ecx,CX(_current_tstamp,%edx) /* set initial time stamp */
+ movl S_ARG0,%ecx /* get timer */
+ movl %ecx,CX(_current_timer,%edx) /* set initial timer */
+ ret
+
+#endif /* accurate timing */
+
+/* */
+
+/*
+ * Trap/interrupt entry points.
+ *
+ * All traps must create the following save area on the kernel stack:
+ *
+ * gs
+ * fs
+ * es
+ * ds
+ * edi
+ * esi
+ * ebp
+ * cr2 if page fault - otherwise unused
+ * ebx
+ * edx
+ * ecx
+ * eax
+ * trap number
+ * error code
+ * eip
+ * cs
+ * eflags
+ * user esp - if from user
+ * user ss - if from user
+ * es - if from V86 thread
+ * ds - if from V86 thread
+ * fs - if from V86 thread
+ * gs - if from V86 thread
+ *
+ */
+
+/*
+ * General protection or segment-not-present fault.
+ * Check for a GP/NP fault in the kernel_return
+ * sequence; if there, report it as a GP/NP fault on the user's instruction.
+ *
+ * esp-> 0: trap code (NP or GP)
+ * 4: segment number in error
+ * 8 eip
+ * 12 cs
+ * 16 eflags
+ * 20 old registers (trap is from kernel)
+ */
+ENTRY(t_gen_prot)
+ pushl $(T_GENERAL_PROTECTION) /* indicate fault type */
+ jmp trap_check_kernel_exit /* check for kernel exit sequence */
+
+ENTRY(t_segnp)
+ pushl $(T_SEGMENT_NOT_PRESENT)
+ /* indicate fault type */
+
+trap_check_kernel_exit:
+ testl $(EFL_VM),16(%esp) /* is trap from V86 mode? */
+ jnz EXT(alltraps) /* isn`t kernel trap if so */
+ testl $3,12(%esp) /* is trap from kernel mode? */
+ jne EXT(alltraps) /* if so: */
+ /* check for the kernel exit sequence */
+ cmpl $_kret_iret,8(%esp) /* on IRET? */
+ je fault_iret
+ cmpl $_kret_popl_ds,8(%esp) /* popping DS? */
+ je fault_popl_ds
+ cmpl $_kret_popl_es,8(%esp) /* popping ES? */
+ je fault_popl_es
+ cmpl $_kret_popl_fs,8(%esp) /* popping FS? */
+ je fault_popl_fs
+ cmpl $_kret_popl_gs,8(%esp) /* popping GS? */
+ je fault_popl_gs
+take_fault: /* if none of the above: */
+ jmp EXT(alltraps) /* treat as normal trap. */
+
+/*
+ * GP/NP fault on IRET: CS or SS is in error.
+ * All registers contain the user's values.
+ *
+ * on SP is
+ * 0 trap number
+ * 4 errcode
+ * 8 eip
+ * 12 cs --> trapno
+ * 16 efl --> errcode
+ * 20 user eip
+ * 24 user cs
+ * 28 user eflags
+ * 32 user esp
+ * 36 user ss
+ */
+fault_iret:
+ movl %eax,8(%esp) /* save eax (we don`t need saved eip) */
+ popl %eax /* get trap number */
+ movl %eax,12-4(%esp) /* put in user trap number */
+ popl %eax /* get error code */
+ movl %eax,16-8(%esp) /* put in user errcode */
+ popl %eax /* restore eax */
+ jmp EXT(alltraps) /* take fault */
+
+/*
+ * Fault restoring a segment register. The user's registers are still
+ * saved on the stack. The offending segment register has not been
+ * popped.
+ */
+fault_popl_ds:
+ popl %eax /* get trap number */
+ popl %edx /* get error code */
+ addl $12,%esp /* pop stack to user regs */
+ jmp push_es /* (DS on top of stack) */
+fault_popl_es:
+ popl %eax /* get trap number */
+ popl %edx /* get error code */
+ addl $12,%esp /* pop stack to user regs */
+ jmp push_fs /* (ES on top of stack) */
+fault_popl_fs:
+ popl %eax /* get trap number */
+ popl %edx /* get error code */
+ addl $12,%esp /* pop stack to user regs */
+ jmp push_gs /* (FS on top of stack) */
+fault_popl_gs:
+ popl %eax /* get trap number */
+ popl %edx /* get error code */
+ addl $12,%esp /* pop stack to user regs */
+ jmp push_segregs /* (GS on top of stack) */
+
+push_es:
+ pushl %es /* restore es, */
+push_fs:
+ pushl %fs /* restore fs, */
+push_gs:
+ pushl %gs /* restore gs. */
+push_segregs:
+ movl %eax,R_TRAPNO(%esp) /* set trap number */
+ movl %edx,R_ERR(%esp) /* set error code */
+ jmp trap_set_segs /* take trap */
+
+/*
+ * Debug trap. Check for single-stepping across system call into
+ * kernel. If this is the case, taking the debug trap has turned
+ * off single-stepping - save the flags register with the trace
+ * bit set.
+ */
+ENTRY(t_debug)
+ testl $(EFL_VM),8(%esp) /* is trap from V86 mode? */
+ jnz 0f /* isn`t kernel trap if so */
+ testl $3,4(%esp) /* is trap from kernel mode? */
+ jnz 0f /* if so: */
+ cmpl $syscall_entry,(%esp) /* system call entry? */
+ jne 0f /* if so: */
+ /* flags are sitting where syscall */
+ /* wants them */
+ addl $8,%esp /* remove eip/cs */
+ jmp syscall_entry_2 /* continue system call entry */
+
+0: pushl $0 /* otherwise: */
+ pushl $(T_DEBUG) /* handle as normal */
+ jmp EXT(alltraps) /* debug fault */
+
+/*
+ * Page fault traps save cr2.
+ */
+ENTRY(t_page_fault)
+ pushl $(T_PAGE_FAULT) /* mark a page fault trap */
+ pusha /* save the general registers */
+ movl %cr2,%eax /* get the faulting address */
+ movl %eax,12(%esp) /* save in esp save slot */
+ jmp trap_push_segs /* continue fault */
+
+/*
+ * All 'exceptions' enter here with:
+ * esp-> trap number
+ * error code
+ * old eip
+ * old cs
+ * old eflags
+ * old esp if trapped from user
+ * old ss if trapped from user
+ */
+ENTRY(alltraps)
+ pusha /* save the general registers */
+trap_push_segs:
+ pushl %ds /* and the segment registers */
+ pushl %es
+ pushl %fs
+ pushl %gs
+
+ /* Note that we have to load the segment registers
+ even if this is a trap from the kernel,
+ because the kernel uses user segment registers for copyin/copyout.
+ (XXX Would it be smarter just to use fs or gs for that?) */
+ mov %ss,%ax /* switch to kernel data segment */
+ mov %ax,%ds /* (same as kernel stack segment) */
+ mov %ax,%es
+
+trap_set_segs:
+ cld /* clear direction flag */
+ testl $(EFL_VM),R_EFLAGS(%esp) /* in V86 mode? */
+ jnz trap_from_user /* user mode trap if so */
+ testb $3,R_CS(%esp) /* user mode trap? */
+ jz trap_from_kernel /* kernel trap if not */
+trap_from_user:
+
+ CPU_NUMBER(%edx)
+ TIME_TRAP_UENTRY
+
+ movl CX(EXT(kernel_stack),%edx),%ebx
+ xchgl %ebx,%esp /* switch to kernel stack */
+ /* user regs pointer already set */
+_take_trap:
+ pushl %ebx /* pass register save area to trap */
+ call EXT(user_trap) /* call user trap routine */
+ movl 4(%esp),%esp /* switch back to PCB stack */
+
+ orl %eax,%eax /* emulated syscall? */
+ jz _return_from_trap /* no, just return */
+ movl R_EAX(%ebx),%eax /* yes, get syscall number */
+ jmp syscall_entry_3 /* and emulate it */
+
+/*
+ * Return from trap or system call, checking for ASTs.
+ * On PCB stack.
+ */
+
+_return_from_trap:
+ CPU_NUMBER(%edx)
+ cmpl $0,CX(EXT(need_ast),%edx)
+ jz _return_to_user /* if we need an AST: */
+
+ movl CX(EXT(kernel_stack),%edx),%esp
+ /* switch to kernel stack */
+ call EXT(i386_astintr) /* take the AST */
+ popl %esp /* switch back to PCB stack */
+ jmp _return_from_trap /* and check again (rare) */
+ /* ASTs after this point will */
+ /* have to wait */
+
+_return_to_user:
+ TIME_TRAP_UEXIT
+
+/*
+ * Return from kernel mode to interrupted thread.
+ */
+
+_return_from_kernel:
+_kret_popl_gs:
+ popl %gs /* restore segment registers */
+_kret_popl_fs:
+ popl %fs
+_kret_popl_es:
+ popl %es
+_kret_popl_ds:
+ popl %ds
+ popa /* restore general registers */
+ addl $8,%esp /* discard trap number and error code */
+_kret_iret:
+ iret /* return from interrupt */
+
+
+/*
+ * Trap from kernel mode. No need to switch stacks.
+ */
+trap_from_kernel:
+#if MACH_KDB || MACH_TTD
+ movl %esp,%ebx /* save current stack */
+
+ cmpl EXT(int_stack_high),%esp /* on an interrupt stack? */
+ jb 1f /* OK if so */
+
+ CPU_NUMBER(%edx) /* get CPU number */
+ cmpl CX(EXT(kernel_stack),%edx),%esp
+ /* already on kernel stack? */
+ ja 0f
+ cmpl CX(EXT(active_stacks),%edx),%esp
+ ja 1f /* switch if not */
+0:
+ movl CX(EXT(kernel_stack),%edx),%esp
+1:
+ pushl %ebx /* save old stack */
+ pushl %ebx /* pass as parameter */
+ call EXT(kernel_trap) /* to kernel trap routine */
+ addl $4,%esp /* pop parameter */
+ popl %esp /* return to old stack */
+#else /* MACH_KDB || MACH_TTD */
+
+ pushl %esp /* pass parameter */
+ call EXT(kernel_trap) /* to kernel trap routine */
+ addl $4,%esp /* pop parameter */
+#endif /* MACH_KDB || MACH_TTD */
+ jmp _return_from_kernel
+
+
+/*
+ * Called as a function, makes the current thread
+ * return from the kernel as if from an exception.
+ */
+
+ENTRY(thread_exception_return)
+ENTRY(thread_bootstrap_return)
+ movl %esp,%ecx /* get kernel stack */
+ or $(KERNEL_STACK_SIZE-1),%ecx
+ movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
+ jmp _return_from_trap
+
+/*
+ * Called as a function, makes the current thread
+ * return from the kernel as if from a syscall.
+ * Takes the syscall's return code as an argument.
+ */
+
+ENTRY(thread_syscall_return)
+ movl S_ARG0,%eax /* get return value */
+ movl %esp,%ecx /* get kernel stack */
+ or $(KERNEL_STACK_SIZE-1),%ecx
+ movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
+ movl %eax,R_EAX(%esp) /* save return value */
+ jmp _return_from_trap
+
+ENTRY(call_continuation)
+ movl S_ARG0,%eax /* get continuation */
+ movl %esp,%ecx /* get kernel stack */
+ or $(KERNEL_STACK_SIZE-1),%ecx
+ addl $(-3-IKS_SIZE),%ecx
+ movl %ecx,%esp /* pop the stack */
+ xorl %ebp,%ebp /* zero frame pointer */
+ jmp *%eax /* goto continuation */
+
+
+
+#define INTERRUPT(n) \
+ .data 2 ;\
+ .long 0f ;\
+ .text ;\
+ P2ALIGN(TEXT_ALIGN) ;\
+0: ;\
+ pushl %eax ;\
+ movl $(n),%eax ;\
+ jmp EXT(all_intrs)
+
+ .data 2
+DATA(int_entry_table)
+ .text
+INTERRUPT(0)
+INTERRUPT(1)
+INTERRUPT(2)
+INTERRUPT(3)
+INTERRUPT(4)
+INTERRUPT(5)
+INTERRUPT(6)
+INTERRUPT(7)
+INTERRUPT(8)
+INTERRUPT(9)
+INTERRUPT(10)
+INTERRUPT(11)
+INTERRUPT(12)
+INTERRUPT(13)
+INTERRUPT(14)
+INTERRUPT(15)
+
+/* XXX handle NMI - at least print a warning like Linux does. */
+
+/*
+ * All interrupts enter here.
+ * old %eax on stack; interrupt number in %eax.
+ */
+ENTRY(all_intrs)
+ pushl %ecx /* save registers */
+ pushl %edx
+ cld /* clear direction flag */
+
+ cmpl %ss:EXT(int_stack_high),%esp /* on an interrupt stack? */
+ jb int_from_intstack /* if not: */
+
+ pushl %ds /* save segment registers */
+ pushl %es
+ mov %ss,%dx /* switch to kernel segments */
+ mov %dx,%ds
+ mov %dx,%es
+
+ CPU_NUMBER(%edx)
+
+ movl CX(EXT(int_stack_top),%edx),%ecx
+ xchgl %ecx,%esp /* switch to interrupt stack */
+
+#if STAT_TIME
+ pushl %ecx /* save pointer to old stack */
+#else
+ pushl %ebx /* save %ebx - out of the way */
+ /* so stack looks the same */
+ pushl %ecx /* save pointer to old stack */
+ TIME_INT_ENTRY /* do timing */
+#endif
+
+ call EXT(interrupt) /* call generic interrupt routine */
+
+ .globl EXT(return_to_iret)
+LEXT(return_to_iret) /* ( label for kdb_kintr and hardclock) */
+
+ CPU_NUMBER(%edx)
+#if STAT_TIME
+#else
+ TIME_INT_EXIT /* do timing */
+ movl 4(%esp),%ebx /* restore the extra reg we saved */
+#endif
+
+ popl %esp /* switch back to old stack */
+
+ testl $(EFL_VM),I_EFL(%esp) /* if in V86 */
+ jnz 0f /* or */
+ testb $3,I_CS(%esp) /* user mode, */
+ jz 1f /* check for ASTs */
+0:
+ cmpl $0,CX(EXT(need_ast),%edx)
+ jnz ast_from_interrupt /* take it if so */
+1:
+ pop %es /* restore segment regs */
+ pop %ds
+ pop %edx
+ pop %ecx
+ pop %eax
+ iret /* return to caller */
+
+int_from_intstack:
+ call EXT(interrupt) /* call interrupt routine */
+_return_to_iret_i: /* ( label for kdb_kintr) */
+ pop %edx /* must have been on kernel segs */
+ pop %ecx
+ pop %eax /* no ASTs */
+ iret
+
+/*
+ * Take an AST from an interrupt.
+ * On PCB stack.
+ * sp-> es -> edx
+ * ds -> ecx
+ * edx -> eax
+ * ecx -> trapno
+ * eax -> code
+ * eip
+ * cs
+ * efl
+ * esp
+ * ss
+ */
+ast_from_interrupt:
+ pop %es /* restore all registers ... */
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ pushl $0 /* zero code */
+ pushl $0 /* zero trap number */
+ pusha /* save general registers */
+ push %ds /* save segment registers */
+ push %es
+ push %fs
+ push %gs
+ mov %ss,%dx /* switch to kernel segments */
+ mov %dx,%ds
+ mov %dx,%es
+
+ CPU_NUMBER(%edx)
+ TIME_TRAP_UENTRY
+
+ movl CX(EXT(kernel_stack),%edx),%esp
+ /* switch to kernel stack */
+ call EXT(i386_astintr) /* take the AST */
+ popl %esp /* back to PCB stack */
+ jmp _return_from_trap /* return */
+
+#if MACH_KDB
+/*
+ * kdb_kintr: enter kdb from keyboard interrupt.
+ * Chase down the stack frames until we find one whose return
+ * address is the interrupt handler. At that point, we have:
+ *
+ * frame-> saved %ebp
+ * return address in interrupt handler
+ * iunit
+ * [ PS2 - saved interrupt number ]
+ * saved SPL
+ * return address == return_to_iret_i
+ * saved %edx
+ * saved %ecx
+ * saved %eax
+ * saved %eip
+ * saved %cs
+ * saved %efl
+ *
+ * OR:
+ * frame-> saved %ebp
+ * return address in interrupt handler
+ * iunit
+ * [ PS2 - saved interrupt number ]
+ * saved SPL
+ * return address == return_to_iret
+ * pointer to save area on old stack
+ * [ saved %ebx, if accurate timing ]
+ *
+ * old stack: saved %es
+ * saved %ds
+ * saved %edx
+ * saved %ecx
+ * saved %eax
+ * saved %eip
+ * saved %cs
+ * saved %efl
+ *
+ * Call kdb, passing it that register save area.
+ */
+
+#ifdef PS2
+#define RET_OFFSET 20
+#else /* not PS2 */
+#define RET_OFFSET 16
+#endif /* PS2 */
+
+ENTRY(kdb_kintr)
+ movl %ebp,%eax /* save caller`s frame pointer */
+ movl $EXT(return_to_iret),%ecx /* interrupt return address 1 */
+ movl $_return_to_iret_i,%edx /* interrupt return address 2 */
+
+0: cmpl RET_OFFSET(%eax),%ecx /* does this frame return to */
+ /* interrupt handler (1)? */
+ je 1f
+ cmpl RET_OFFSET(%eax),%edx /* interrupt handler (2)? */
+ je 2f /* if not: */
+ movl (%eax),%eax /* try next frame */
+ jmp 0b
+
+1: movl $kdb_from_iret,RET_OFFSET(%eax)
+ ret /* returns to kernel/user stack */
+
+2: movl $kdb_from_iret_i,RET_OFFSET(%eax)
+ /* returns to interrupt stack */
+ ret
+
+/*
+ * On return from keyboard interrupt, we will execute
+ * kdb_from_iret_i
+ * if returning to an interrupt on the interrupt stack
+ * kdb_from_iret
+ * if returning to an interrupt on the user or kernel stack
+ */
+kdb_from_iret:
+ /* save regs in known locations */
+#if STAT_TIME
+ pushl %ebx /* caller`s %ebx is in reg */
+#else
+ movl 4(%esp),%eax /* get caller`s %ebx */
+ pushl %eax /* push on stack */
+#endif
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ push %fs
+ push %gs
+ pushl %esp /* pass regs */
+ call EXT(kdb_kentry) /* to kdb */
+ addl $4,%esp /* pop parameters */
+ pop %gs /* restore registers */
+ pop %fs
+ popl %edi
+ popl %esi
+ popl %ebp
+#if STAT_TIME
+ popl %ebx
+#else
+ popl %eax
+ movl %eax,4(%esp)
+#endif
+ jmp EXT(return_to_iret) /* normal interrupt return */
+
+kdb_from_iret_i: /* on interrupt stack */
+ pop %edx /* restore saved registers */
+ pop %ecx
+ pop %eax
+ pushl $0 /* zero error code */
+ pushl $0 /* zero trap number */
+ pusha /* save general registers */
+ push %ds /* save segment registers */
+ push %es
+ push %fs
+ push %gs
+ pushl %esp /* pass regs, */
+ pushl $0 /* code, */
+ pushl $-1 /* type to kdb */
+ call EXT(kdb_trap)
+ addl $12,%esp /* remove parameters */
+ pop %gs /* restore segment registers */
+ pop %fs
+ pop %es
+ pop %ds
+ popa /* restore general registers */
+ addl $8,%esp
+ iret
+
+#endif MACH_KDB
+
+#if MACH_TTD
+/*
+ * Same code as that above for the keyboard entry into kdb.
+ */
+ENTRY(kttd_intr)
+ movl %ebp,%eax /* save caller`s frame pointer */
+ movl $EXT(return_to_iret),%ecx /* interrupt return address 1 */
+ movl $_return_to_iret_i,%edx /* interrupt return address 2 */
+
+0: cmpl 16(%eax),%ecx /* does this frame return to */
+ /* interrupt handler (1)? */
+ je 1f
+ cmpl 16(%eax),%edx /* interrupt handler (2)? */
+ je 2f /* if not: */
+ movl (%eax),%eax /* try next frame */
+ jmp 0b
+
+1: movl $ttd_from_iret,16(%eax) /* returns to kernel/user stack */
+ ret
+
+2: movl $ttd_from_iret_i,16(%eax)
+ /* returns to interrupt stack */
+ ret
+
+/*
+ * On return from keyboard interrupt, we will execute
+ * ttd_from_iret_i
+ * if returning to an interrupt on the interrupt stack
+ * ttd_from_iret
+ * if returning to an interrupt on the user or kernel stack
+ */
+ttd_from_iret:
+ /* save regs in known locations */
+#if STAT_TIME
+ pushl %ebx /* caller`s %ebx is in reg */
+#else
+ movl 4(%esp),%eax /* get caller`s %ebx */
+ pushl %eax /* push on stack */
+#endif
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ push %fs
+ push %gs
+ pushl %esp /* pass regs */
+ call _kttd_netentry /* to kdb */
+ addl $4,%esp /* pop parameters */
+ pop %gs /* restore registers */
+ pop %fs
+ popl %edi
+ popl %esi
+ popl %ebp
+#if STAT_TIME
+ popl %ebx
+#else
+ popl %eax
+ movl %eax,4(%esp)
+#endif
+ jmp EXT(return_to_iret) /* normal interrupt return */
+
+ttd_from_iret_i: /* on interrupt stack */
+ pop %edx /* restore saved registers */
+ pop %ecx
+ pop %eax
+ pushl $0 /* zero error code */
+ pushl $0 /* zero trap number */
+ pusha /* save general registers */
+ push %ds /* save segment registers */
+ push %es
+ push %fs
+ push %gs
+ pushl %esp /* pass regs, */
+ pushl $0 /* code, */
+ pushl $-1 /* type to kdb */
+ call _kttd_trap
+ addl $12,%esp /* remove parameters */
+ pop %gs /* restore segment registers */
+ pop %fs
+ pop %es
+ pop %ds
+ popa /* restore general registers */
+ addl $8,%esp
+ iret
+
+#endif /* MACH_TTD */
+
+/*
+ * System call enters through a call gate. Flags are not saved -
+ * we must shuffle stack to look like trap save area.
+ *
+ * esp-> old eip
+ * old cs
+ * old esp
+ * old ss
+ *
+ * eax contains system call number.
+ */
+ENTRY(syscall)
+syscall_entry:
+ pushf /* save flags as soon as possible */
+syscall_entry_2:
+ pushl %eax /* save system call number */
+ pushl $0 /* clear trap number slot */
+
+ pusha /* save the general registers */
+ pushl %ds /* and the segment registers */
+ pushl %es
+ pushl %fs
+ pushl %gs
+
+ mov %ss,%dx /* switch to kernel data segment */
+ mov %dx,%ds
+ mov %dx,%es
+
+/*
+ * Shuffle eflags,eip,cs into proper places
+ */
+
+ movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
+ movl R_CS(%esp),%ecx /* eip is in CS slot */
+ movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
+ movl %ecx,R_EIP(%esp) /* fix eip */
+ movl %edx,R_CS(%esp) /* fix cs */
+ movl %ebx,R_EFLAGS(%esp) /* fix eflags */
+
+ CPU_NUMBER(%edx)
+ TIME_TRAP_SENTRY
+
+ movl CX(EXT(kernel_stack),%edx),%ebx
+ /* get current kernel stack */
+ xchgl %ebx,%esp /* switch stacks - %ebx points to */
+ /* user registers. */
+ /* user regs pointer already set */
+
+/*
+ * Check for MACH or emulated system call
+ */
+syscall_entry_3:
+ movl CX(EXT(active_threads),%edx),%edx
+ /* point to current thread */
+ movl TH_TASK(%edx),%edx /* point to task */
+ movl TASK_EMUL(%edx),%edx /* get emulation vector */
+ orl %edx,%edx /* if none, */
+ je syscall_native /* do native system call */
+ movl %eax,%ecx /* copy system call number */
+ subl DISP_MIN(%edx),%ecx /* get displacement into syscall */
+ /* vector table */
+ jl syscall_native /* too low - native system call */
+ cmpl DISP_COUNT(%edx),%ecx /* check range */
+ jnl syscall_native /* too high - native system call */
+ movl DISP_VECTOR(%edx,%ecx,4),%edx
+ /* get the emulation vector */
+ orl %edx,%edx /* emulated system call if not zero */
+ jnz syscall_emul
+
+/*
+ * Native system call.
+ */
+syscall_native:
+ negl %eax /* get system call number */
+ jl mach_call_range /* out of range if it was positive */
+ cmpl EXT(mach_trap_count),%eax /* check system call table bounds */
+ jg mach_call_range /* error if out of range */
+#if 0 /* debug hack to show the syscall number on the screen */
+ movb %al,%dl
+ shrb $4,%dl
+ orb $0x30,%dl
+ movb $0x0f,%dh
+ movw %dx,0xb800a
+ movb %al,%dl
+ andb $0xf,%dl
+ orb $0x30,%dl
+ movb $0xf,%dh
+ movw %dx,0xb800c
+#endif
+ shll $4,%eax /* manual indexing */
+ movl EXT(mach_trap_table)(%eax),%ecx
+ /* get number of arguments */
+ jecxz mach_call_call /* skip argument copy if none */
+
+ movl R_UESP(%ebx),%esi /* get user stack pointer */
+ lea 4(%esi,%ecx,4),%esi /* skip user return address, */
+ /* and point past last argument */
+ movl $USER_DS,%edx /* use user data segment for accesses */
+ mov %dx,%fs
+ movl %esp,%edx /* save kernel ESP for error recovery */
+
+0: subl $4,%esi
+ RECOVER(mach_call_addr_push)
+ pushl %fs:(%esi) /* push argument on stack */
+ loop 0b /* loop for all arguments */
+
+mach_call_call:
+
+#ifdef DEBUG
+ testb $0xff,EXT(syscall_trace)
+ jz 0f
+ pushl %eax
+ call EXT(syscall_trace_print)
+ /* will return with syscallofs still (or again) in eax */
+ addl $4,%esp
+0:
+#endif DEBUG
+
+ call *EXT(mach_trap_table)+4(%eax)
+ /* call procedure */
+ movl %esp,%ecx /* get kernel stack */
+ or $(KERNEL_STACK_SIZE-1),%ecx
+ movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
+ movl %eax,R_EAX(%esp) /* save return value */
+ jmp _return_from_trap /* return to user */
+
+/*
+ * Address out of range. Change to page fault.
+ * %esi holds failing address.
+ */
+mach_call_addr_push:
+ movl %edx,%esp /* clean parameters from stack */
+mach_call_addr:
+ movl %esi,R_CR2(%ebx) /* set fault address */
+ movl $(T_PAGE_FAULT),R_TRAPNO(%ebx)
+ /* set page-fault trap */
+ movl $(T_PF_USER),R_ERR(%ebx)
+ /* set error code - read user space */
+ jmp _take_trap /* treat as a trap */
+
+/*
+ * System call out of range. Treat as invalid-instruction trap.
+ * (? general protection?)
+ */
+mach_call_range:
+ movl $(T_INVALID_OPCODE),R_TRAPNO(%ebx)
+ /* set invalid-operation trap */
+ movl $0,R_ERR(%ebx) /* clear error code */
+ jmp _take_trap /* treat as a trap */
+
+/*
+ * User space emulation of system calls.
+ * edx - user address to handle syscall
+ *
+ * User stack will become:
+ * uesp-> eflags
+ * eip
+ * eax still contains syscall number.
+ */
+syscall_emul:
+ movl $USER_DS,%edi /* use user data segment for accesses */
+ mov %di,%fs
+
+/* XXX what about write-protected pages? */
+ movl R_UESP(%ebx),%edi /* get user stack pointer */
+ subl $8,%edi /* push space for new arguments */
+ movl R_EFLAGS(%ebx),%eax /* move flags */
+ RECOVER(syscall_addr)
+ movl %eax,%fs:0(%edi) /* to user stack */
+ movl R_EIP(%ebx),%eax /* move eip */
+ RECOVER(syscall_addr)
+ movl %eax,%fs:4(%edi) /* to user stack */
+ movl %edi,R_UESP(%ebx) /* set new user stack pointer */
+ movl %edx,R_EIP(%ebx) /* change return address to trap */
+ movl %ebx,%esp /* back to PCB stack */
+ jmp _return_from_trap /* return to user */
+
+/*
+ * Address error - address is in %edi.
+ */
+syscall_addr:
+ movl %edi,R_CR2(%ebx) /* set fault address */
+ movl $(T_PAGE_FAULT),R_TRAPNO(%ebx)
+ /* set page-fault trap */
+ movl $(T_PF_USER),R_ERR(%ebx)
+ /* set error code - read user space */
+ jmp _take_trap /* treat as a trap */
+
+/* */
+/*
+ * Utility routines.
+ */
+
+/*
+ * Copy from user address space.
+ * arg0: user address
+ * arg1: kernel address
+ * arg2: byte count
+ */
+ENTRY(copyin)
+Entry(copyinmsg)
+ pushl %esi
+ pushl %edi /* save registers */
+
+ movl 8+S_ARG0,%esi /* get user start address */
+ movl 8+S_ARG1,%edi /* get kernel destination address */
+ movl 8+S_ARG2,%edx /* get count */
+
+ movl $USER_DS,%eax /* use user data segment for accesses */
+ mov %ax,%ds
+
+ /*cld*/ /* count up: default mode in all GCC code */
+ movl %edx,%ecx /* move by longwords first */
+ shrl $2,%ecx
+ RECOVER(copyin_fail)
+ rep
+ movsl /* move longwords */
+ movl %edx,%ecx /* now move remaining bytes */
+ andl $3,%ecx
+ RECOVER(copyin_fail)
+ rep
+ movsb
+ xorl %eax,%eax /* return 0 for success */
+
+copyin_ret:
+ mov %ss,%di /* restore DS to kernel segment */
+ mov %di,%ds
+
+ popl %edi /* restore registers */
+ popl %esi
+ ret /* and return */
+
+copyin_fail:
+ movl $1,%eax /* return 1 for failure */
+ jmp copyin_ret /* pop frame and return */
+
+/*
+ * Copy to user address space.
+ * arg0: kernel address
+ * arg1: user address
+ * arg2: byte count
+ */
+ENTRY(copyout)
+Entry(copyoutmsg)
+ pushl %esi
+ pushl %edi /* save registers */
+
+ movl 8+S_ARG0,%esi /* get kernel start address */
+ movl 8+S_ARG1,%edi /* get user start address */
+ movl 8+S_ARG2,%edx /* get count */
+
+ movl $USER_DS,%eax /* use user data segment for accesses */
+ mov %ax,%es
+
+/*
+ * Check whether user address space is writable
+ * before writing to it - hardware is broken.
+ * XXX only have to do this on 386's.
+ */
+copyout_retry:
+ movl %cr3,%ecx /* point to page directory */
+ movl %edi,%eax /* get page directory bits */
+ shrl $(PDESHIFT),%eax /* from user address */
+ movl KERNELBASE(%ecx,%eax,4),%ecx
+ /* get page directory pointer */
+ testl $(PTE_V),%ecx /* present? */
+ jz 0f /* if not, fault is OK */
+ andl $(PTE_PFN),%ecx /* isolate page frame address */
+ movl %edi,%eax /* get page table bits */
+ shrl $(PTESHIFT),%eax
+ andl $(PTEMASK),%eax /* from user address */
+ leal KERNELBASE(%ecx,%eax,4),%ecx
+ /* point to page table entry */
+ movl (%ecx),%eax /* get it */
+ testl $(PTE_V),%eax /* present? */
+ jz 0f /* if not, fault is OK */
+ testl $(PTE_W),%eax /* writable? */
+ jnz 0f /* OK if so */
+/*
+ * Not writable - must fake a fault. Turn off access to the page.
+ */
+ andl $(PTE_INVALID),(%ecx) /* turn off valid bit */
+ movl %cr3,%eax /* invalidate TLB */
+ movl %eax,%cr3
+0:
+
+/*
+ * Copy only what fits on the current destination page.
+ * Check for write-fault again on the next page.
+ */
+ leal NBPG(%edi),%eax /* point to */
+ andl $(-NBPG),%eax /* start of next page */
+ subl %edi,%eax /* get number of bytes to that point */
+ cmpl %edx,%eax /* bigger than count? */
+ jle 1f /* if so, */
+ movl %edx,%eax /* use count */
+1:
+
+ /*cld*/ /* count up: always this way in GCC code */
+ movl %eax,%ecx /* move by longwords first */
+ shrl $2,%ecx
+ RECOVER(copyout_fail)
+ RETRY(copyout_retry)
+ rep
+ movsl
+ movl %eax,%ecx /* now move remaining bytes */
+ andl $3,%ecx
+ RECOVER(copyout_fail)
+ RETRY(copyout_retry)
+ rep
+ movsb /* move */
+ subl %eax,%edx /* decrement count */
+ jg copyout_retry /* restart on next page if not done */
+ xorl %eax,%eax /* return 0 for success */
+
+copyout_ret:
+ mov %ss,%di /* restore ES to kernel segment */
+ mov %di,%es
+
+ popl %edi /* restore registers */
+ popl %esi
+ ret /* and return */
+
+copyout_fail:
+ movl $1,%eax /* return 1 for failure */
+ jmp copyout_ret /* pop frame and return */
+
+/* XXX turn the following stubs into inline functions. */
+
+/*
+ * FPU routines.
+ */
+
+/*
+ * Initialize FPU.
+ */
+ENTRY(_fninit)
+ fninit
+ ret
+
+/*
+ * Read control word
+ */
+ENTRY(_fstcw)
+ pushl %eax /* get stack space */
+ fstcw (%esp)
+ popl %eax
+ ret
+
+/*
+ * Set control word
+ */
+ENTRY(_fldcw)
+ fldcw 4(%esp)
+ ret
+
+/*
+ * Read status word
+ */
+ENTRY(_fnstsw)
+ xor %eax,%eax /* clear high 16 bits of eax */
+ fnstsw %ax /* read FP status */
+ ret
+
+/*
+ * Clear FPU exceptions
+ */
+ENTRY(_fnclex)
+ fnclex
+ ret
+
+/*
+ * Clear task-switched flag.
+ */
+ENTRY(_clts)
+ clts
+ ret
+
+/*
+ * Save complete FPU state. Save error for later.
+ */
+ENTRY(_fpsave)
+ movl 4(%esp),%eax /* get save area pointer */
+ fnsave (%eax) /* save complete state, including */
+ /* errors */
+ ret
+
+/*
+ * Restore FPU state.
+ */
+ENTRY(_fprestore)
+ movl 4(%esp),%eax /* get save area pointer */
+ frstor (%eax) /* restore complete state */
+ ret
+
+/*
+ * Set cr3
+ */
+ENTRY(set_cr3)
+ movl 4(%esp),%eax /* get new cr3 value */
+ movl %eax,%cr3 /* load it */
+ ret
+
+/*
+ * Read cr3
+ */
+ENTRY(get_cr3)
+ movl %cr3,%eax
+ ret
+
+/*
+ * Flush TLB
+ */
+ENTRY(flush_tlb)
+ movl %cr3,%eax /* flush tlb by reloading CR3 */
+ movl %eax,%cr3 /* with itself */
+ ret
+
+/*
+ * Read cr2
+ */
+ENTRY(get_cr2)
+ movl %cr2,%eax
+ ret
+
+/*
+ * Read ldtr
+ */
+ENTRY(get_ldt)
+ xorl %eax,%eax
+ sldt %ax
+ ret
+
+/*
+ * Set ldtr
+ */
+ENTRY(set_ldt)
+ lldt 4(%esp)
+ ret
+
+/*
+ * Read task register.
+ */
+ENTRY(get_tr)
+ xorl %eax,%eax
+ str %ax
+ ret
+
+/*
+ * Set task register. Also clears busy bit of task descriptor.
+ */
+ENTRY(set_tr)
+ movl S_ARG0,%eax /* get task segment number */
+ subl $8,%esp /* push space for SGDT */
+ sgdt 2(%esp) /* store GDT limit and base (linear) */
+ movl 4(%esp),%edx /* address GDT */
+ movb $(ACC_P|ACC_PL_K|ACC_TSS),5(%edx,%eax)
+ /* fix access byte in task descriptor */
+ ltr %ax /* load task register */
+ addl $8,%esp /* clear stack */
+ ret /* and return */
+
+/*
+ * Set task-switched flag.
+ */
+ENTRY(_setts)
+ movl %cr0,%eax /* get cr0 */
+ orl $(CR0_TS),%eax /* or in TS bit */
+ movl %eax,%cr0 /* set cr0 */
+ ret
+
+/*
+ * void outb(unsigned char *io_port,
+ * unsigned char byte)
+ *
+ * Output a byte to an IO port.
+ */
+ENTRY(outb)
+ movl S_ARG0,%edx /* IO port address */
+ movl S_ARG1,%eax /* data to output */
+ outb %al,%dx /* send it out */
+#ifdef iPSC386
+ mull %ecx /* Delay a little to make H/W happy */
+#endif iPSC386
+ ret
+
+/*
+ * unsigned char inb(unsigned char *io_port)
+ *
+ * Input a byte from an IO port.
+ */
+ENTRY(inb)
+ movl S_ARG0,%edx /* IO port address */
+ xor %eax,%eax /* clear high bits of register */
+ inb %dx,%al /* get the byte */
+#ifdef iPSC386
+/ Do a long multiply to delay a little to make H/W happy. Must
+/ save and restore EAX which is used to hold result of multiply
+ pushl %eax
+ mull %ecx
+ popl %eax
+#endif iPSC386
+ ret
+
+/*
+ * void outw(unsigned short *io_port,
+ * unsigned short word)
+ *
+ * Output a word to an IO port.
+ */
+ENTRY(outw)
+ movl S_ARG0,%edx /* IO port address */
+ movl S_ARG1,%eax /* data to output */
+ outw %ax,%dx /* send it out */
+ ret
+
+/*
+ * unsigned short inw(unsigned short *io_port)
+ *
+ * Input a word from an IO port.
+ */
+ENTRY(inw)
+ movl S_ARG0,%edx /* IO port address */
+ xor %eax,%eax /* clear high bits of register */
+ inw %dx,%ax /* get the word */
+ ret
+
+/*
+ * void outl(unsigned int *io_port,
+ * unsigned int byte)
+ *
+ * Output an int to an IO port.
+ */
+ENTRY(outl)
+ movl S_ARG0,%edx /* IO port address */
+ movl S_ARG1,%eax /* data to output */
+ outl %eax,%dx /* send it out */
+ ret
+
+/*
+ * unsigned int inl(unsigned int *io_port)
+ *
+ * Input an int from an IO port.
+ */
+ENTRY(inl)
+ movl S_ARG0,%edx /* IO port address */
+ inl %dx,%eax /* get the int */
+ ret
+
+/*
+ * void loutb(unsigned byte *io_port,
+ * unsigned byte *data,
+ * unsigned int count)
+ *
+ * Output an array of bytes to an IO port.
+ */
+ENTRY(loutb)
+ movl %esi,%eax /* save register */
+ movl S_ARG0,%edx /* get io port number */
+ movl S_ARG1,%esi /* get data address */
+ movl S_ARG2,%ecx /* get count */
+
+ cld /* count up */
+
+ rep
+ outsb /* output */
+
+ movl %eax,%esi /* restore register */
+ ret /* exit */
+
+
+/*
+ * void loutw(unsigned short *io_port,
+ * unsigned short *data,
+ * unsigned int count)
+ *
+ * Output an array of shorts to an IO port.
+ */
+ENTRY(loutw)
+ movl %esi,%eax /* save register */
+ movl S_ARG0,%edx /* get io port number */
+ movl S_ARG1,%esi /* get data address */
+ movl S_ARG2,%ecx /* get count */
+
+ cld /* count up */
+
+ rep
+ outsw /* output */
+
+ movl %eax,%esi /* restore register */
+ ret /* exit */
+
+
+/*
+ * void linb(unsigned char *io_port,
+ * unsigned char *data,
+ * unsigned int count)
+ *
+ * Input an array of bytes from an IO port.
+ */
+ENTRY(linb)
+ movl %edi,%eax /* save register */
+ movl S_ARG0,%edx /* get io port number */
+ movl S_ARG1,%edi /* get data address */
+ movl S_ARG2,%ecx /* get count */
+
+ cld /* count up */
+
+ rep
+ insb /* input */
+
+ movl %eax,%edi /* restore register */
+ ret /* exit */
+
+
+/*
+ * void linw(unsigned short *io_port,
+ * unsigned short *data,
+ * unsigned int count)
+ *
+ * Input an array of shorts from an IO port.
+ */
+ENTRY(linw)
+ movl %edi,%eax /* save register */
+ movl S_ARG0,%edx /* get io port number */
+ movl S_ARG1,%edi /* get data address */
+ movl S_ARG2,%ecx /* get count */
+
+ cld /* count up */
+
+ rep
+ insw /* input */
+
+ movl %eax,%edi /* restore register */
+ ret /* exit */
+
+
+/*
+ * int inst_fetch(int eip, int cs);
+ *
+ * Fetch instruction byte. Return -1 if invalid address.
+ */
+ENTRY(inst_fetch)
+ movl S_ARG1, %eax /* get segment */
+ movw %ax,%fs /* into FS */
+ movl S_ARG0, %eax /* get offset */
+ RETRY(EXT(inst_fetch)) /* re-load FS on retry */
+ RECOVER(_inst_fetch_fault)
+ movzbl %fs:(%eax),%eax /* load instruction byte */
+ ret
+
+_inst_fetch_fault:
+ movl $-1,%eax /* return -1 if error */
+ ret
+
+
+/*
+ * Done with recovery and retry tables.
+ */
+ RECOVER_TABLE_END
+ RETRY_TABLE_END
+
+
+
+ENTRY(dr6)
+ movl %db6, %eax
+ ret
+
+/* dr<i>(address, type, len, persistence)
+ */
+ENTRY(dr0)
+ movl S_ARG0, %eax
+ movl %eax,EXT(dr_addr)
+ movl %eax, %db0
+ movl $0, %ecx
+ jmp 0f
+ENTRY(dr1)
+ movl S_ARG0, %eax
+ movl %eax,EXT(dr_addr)+1*4
+ movl %eax, %db1
+ movl $2, %ecx
+ jmp 0f
+ENTRY(dr2)
+ movl S_ARG0, %eax
+ movl %eax,EXT(dr_addr)+2*4
+ movl %eax, %db2
+ movl $4, %ecx
+ jmp 0f
+
+ENTRY(dr3)
+ movl S_ARG0, %eax
+ movl %eax,EXT(dr_addr)+3*4
+ movl %eax, %db3
+ movl $6, %ecx
+
+0:
+ pushl %ebp
+ movl %esp, %ebp
+
+ movl %db7, %edx
+ movl %edx,EXT(dr_addr)+4*4
+ andl dr_msk(,%ecx,2),%edx /* clear out new entry */
+ movl %edx,EXT(dr_addr)+5*4
+ movzbl B_ARG3, %eax
+ andb $3, %al
+ shll %cl, %eax
+ orl %eax, %edx
+
+ movzbl B_ARG1, %eax
+ andb $3, %al
+ addb $0x10, %ecx
+ shll %cl, %eax
+ orl %eax, %edx
+
+ movzbl B_ARG2, %eax
+ andb $3, %al
+ addb $0x2, %ecx
+ shll %cl, %eax
+ orl %eax, %edx
+
+ movl %edx, %db7
+ movl %edx,EXT(dr_addr)+7*4
+ movl %edx, %eax
+ leave
+ ret
+
+ .data
+dr_msk:
+ .long ~0x000f0003
+ .long ~0x00f0000c
+ .long ~0x0f000030
+ .long ~0xf00000c0
+ENTRY(dr_addr)
+ .long 0,0,0,0
+ .long 0,0,0,0
+ .text
+
+/*
+ * Waste 10 microseconds.
+ */
+ENTRY(tenmicrosec)
+ movl EXT(microdata),%ecx /* cycle count for 10 microsecond loop */
+tenmicroloop:
+ loop tenmicroloop
+ ret
+
+/*
+ * cpu_shutdown()
+ * Force reboot
+ */
+null_idtr:
+ .word 0
+ .long 0
+
+Entry(cpu_shutdown)
+ lidt null_idtr /* disable the interrupt handler */
+ xor %ecx,%ecx /* generate a divide by zero */
+ div %ecx,%eax /* reboot now */
+ ret /* this will "never" be executed */
+
+
+/*
+ * Allocate enough space for a kernel TSS with a complete I/O bitmap,
+ * for making v86-mode BIOS calls. XXX
+ */
+ .data
+ .globl EXT(ktss)
+ .comm EXT(ktss),0x68+65536/8+1
+
diff --git a/i386/i386/loose_ends.c b/i386/i386/loose_ends.c
new file mode 100644
index 00000000..6a10adc3
--- /dev/null
+++ b/i386/i386/loose_ends.c
@@ -0,0 +1,82 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ */
+#include <mach_assert.h>
+
+
+ /*
+ * For now we will always go to single user mode, since there is
+ * no way pass this request through the boot.
+ */
+int boothowto = 0;
+
+ /*
+ * Should be rewritten in asm anyway.
+ */
+/*
+ * ovbcopy - like bcopy, but recognizes overlapping ranges and handles
+ * them correctly.
+ */
+ovbcopy(from, to, bytes)
+ char *from, *to;
+ int bytes; /* num bytes to copy */
+{
+ /* Assume that bcopy copies left-to-right (low addr first). */
+ if (from + bytes <= to || to + bytes <= from || to == from)
+ bcopy(from, to, bytes); /* non-overlapping or no-op*/
+ else if (from > to)
+ bcopy(from, to, bytes); /* overlapping but OK */
+ else {
+ /* to > from: overlapping, and must copy right-to-left. */
+ from += bytes - 1;
+ to += bytes - 1;
+ while (bytes-- > 0)
+ *to-- = *from--;
+ }
+}
+
+/* Someone with time should write code to set cpuspeed automagically */
+int cpuspeed = 4;
+#define DELAY(n) { register int N = cpuspeed * (n); while (--N > 0); }
+delay(n)
+{
+ DELAY(n);
+}
+
+#if MACH_ASSERT
+
+/*
+ * Machine-dependent routine to fill in an array with up to callstack_max
+ * levels of return pc information.
+ */
+void machine_callstack(
+ unsigned long *buf,
+ int callstack_max)
+{
+}
+
+#endif /* MACH_ASSERT */
diff --git a/i386/i386/mach_i386.srv b/i386/i386/mach_i386.srv
new file mode 100644
index 00000000..48d16ba4
--- /dev/null
+++ b/i386/i386/mach_i386.srv
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+/* This is a server presentation file. */
+
+#define KERNEL_SERVER 1
+
+#include <mach/machine/mach_i386.defs>
diff --git a/i386/i386/mach_param.h b/i386/i386/mach_param.h
new file mode 100644
index 00000000..d7d4deee
--- /dev/null
+++ b/i386/i386/mach_param.h
@@ -0,0 +1,31 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Machine-dependent parameters for i386.
+ */
+
+#define HZ (100)
+ /* clock tick each 10 ms. */
diff --git a/i386/i386/machine_routines.h b/i386/i386/machine_routines.h
new file mode 100644
index 00000000..a1fb489e
--- /dev/null
+++ b/i386/i386/machine_routines.h
@@ -0,0 +1,37 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_MACHINE_ROUTINES_H_
+#define _I386_MACHINE_ROUTINES_H_
+
+/*
+ * The i386 has a set of machine-dependent interfaces.
+ */
+#define MACHINE_SERVER mach_i386_server
+#define MACHINE_SERVER_ROUTINE mach_i386_server_routine
+
+#endif
+
diff --git a/i386/i386/machspl.h b/i386/i386/machspl.h
new file mode 100644
index 00000000..bbb26754
--- /dev/null
+++ b/i386/i386/machspl.h
@@ -0,0 +1,29 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* XXX replaced by... */
+#include <i386/spl.h>
+
diff --git a/i386/i386/mp_desc.c b/i386/i386/mp_desc.c
new file mode 100644
index 00000000..d7b4f61e
--- /dev/null
+++ b/i386/i386/mp_desc.c
@@ -0,0 +1,235 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <cpus.h>
+
+#if NCPUS > 1
+
+#include <kern/cpu_number.h>
+#include <mach/machine.h>
+#include <vm/vm_kern.h>
+
+#include <i386/mp_desc.h>
+#include <i386/lock.h>
+
+/*
+ * The i386 needs an interrupt stack to keep the PCB stack from being
+ * overrun by interrupts. All interrupt stacks MUST lie at lower addresses
+ * than any thread`s kernel stack.
+ */
+
+/*
+ * Addresses of bottom and top of interrupt stacks.
+ */
+vm_offset_t interrupt_stack[NCPUS];
+vm_offset_t int_stack_top[NCPUS];
+
+/*
+ * Barrier address.
+ */
+vm_offset_t int_stack_high;
+
+/*
+ * First cpu`s interrupt stack.
+ */
+char intstack[]; /* bottom */
+char eintstack[]; /* top */
+
+/*
+ * We allocate interrupt stacks from physical memory.
+ */
+extern
+vm_offset_t avail_start;
+
+/*
+ * Multiprocessor i386/i486 systems use a separate copy of the
+ * GDT, IDT, LDT, and kernel TSS per processor. The first three
+ * are separate to avoid lock contention: the i386 uses locked
+ * memory cycles to access the descriptor tables. The TSS is
+ * separate since each processor needs its own kernel stack,
+ * and since using a TSS marks it busy.
+ */
+
+/*
+ * Allocated descriptor tables.
+ */
+struct mp_desc_table *mp_desc_table[NCPUS] = { 0 };
+
+/*
+ * Pointer to TSS for access in load_context.
+ */
+struct i386_tss *mp_ktss[NCPUS] = { 0 };
+
+/*
+ * Pointer to GDT to reset the KTSS busy bit.
+ */
+struct real_descriptor *mp_gdt[NCPUS] = { 0 };
+
+/*
+ * Boot-time tables, for initialization and master processor.
+ */
+extern struct real_gate idt[IDTSZ];
+extern struct real_descriptor gdt[GDTSZ];
+extern struct real_descriptor ldt[LDTSZ];
+extern struct i386_tss ktss;
+
+/*
+ * Allocate and initialize the per-processor descriptor tables.
+ */
+
+struct mp_desc_table *
+mp_desc_init(mycpu)
+ register int mycpu;
+{
+ register struct mp_desc_table *mpt;
+
+ if (mycpu == master_cpu) {
+ /*
+ * Master CPU uses the tables built at boot time.
+ * Just set the TSS and GDT pointers.
+ */
+ mp_ktss[mycpu] = &ktss;
+ mp_gdt[mycpu] = gdt;
+ return 0;
+ }
+ else {
+ /*
+ * Other CPUs allocate the table from the bottom of
+ * the interrupt stack.
+ */
+ mpt = (struct mp_desc_table *) interrupt_stack[mycpu];
+
+ mp_desc_table[mycpu] = mpt;
+ mp_ktss[mycpu] = &mpt->ktss;
+ mp_gdt[mycpu] = mpt->gdt;
+
+ /*
+ * Copy the tables
+ */
+ bcopy((char *)idt,
+ (char *)mpt->idt,
+ sizeof(idt));
+ bcopy((char *)gdt,
+ (char *)mpt->gdt,
+ sizeof(gdt));
+ bcopy((char *)ldt,
+ (char *)mpt->ldt,
+ sizeof(ldt));
+ bzero((char *)&mpt->ktss,
+ sizeof(struct i386_tss));
+
+ /*
+ * Fix up the entries in the GDT to point to
+ * this LDT and this TSS.
+ */
+ fill_descriptor(&mpt->gdt[sel_idx(KERNEL_LDT)],
+ (unsigned)&mpt->ldt,
+ LDTSZ * sizeof(struct real_descriptor) - 1,
+ ACC_P|ACC_PL_K|ACC_LDT, 0);
+ fill_descriptor(&mpt->gdt[sel_idx(KERNEL_TSS)],
+ (unsigned)&mpt->ktss,
+ sizeof(struct i386_tss) - 1,
+ ACC_P|ACC_PL_K|ACC_TSS, 0);
+
+ mpt->ktss.ss0 = KERNEL_DS;
+ mpt->ktss.io_bit_map_offset = 0x0FFF; /* no IO bitmap */
+
+ return mpt;
+ }
+}
+
+
+/*
+ * Called after all CPUs have been found, but before the VM system
+ * is running. The machine array must show which CPUs exist.
+ */
+void
+interrupt_stack_alloc()
+{
+ register int i;
+ int cpu_count;
+ vm_offset_t stack_start;
+
+ /*
+ * Count the number of CPUs.
+ */
+ cpu_count = 0;
+ for (i = 0; i < NCPUS; i++)
+ if (machine_slot[i].is_cpu)
+ cpu_count++;
+
+ /*
+ * Allocate an interrupt stack for each CPU except for
+ * the master CPU (which uses the bootstrap stack)
+ */
+ if (!init_alloc(INTSTACK_SIZE*(cpu_count-1), &stack_start))
+ panic("not enough memory for interrupt stacks");
+
+ /*
+ * Set up pointers to the top of the interrupt stack.
+ */
+ for (i = 0; i < NCPUS; i++) {
+ if (i == master_cpu) {
+ interrupt_stack[i] = (vm_offset_t) intstack;
+ int_stack_top[i] = (vm_offset_t) eintstack;
+ }
+ else if (machine_slot[i].is_cpu) {
+ interrupt_stack[i] = stack_start;
+ int_stack_top[i] = stack_start + INTSTACK_SIZE;
+
+ stack_start += INTSTACK_SIZE;
+ }
+ }
+
+ /*
+ * Set up the barrier address. All thread stacks MUST
+ * be above this address.
+ */
+ int_stack_high = stack_start;
+}
+
+/* XXX should be adjusted per CPU speed */
+int simple_lock_pause_loop = 100;
+
+unsigned int simple_lock_pause_count = 0; /* debugging */
+
+void
+simple_lock_pause()
+{
+ static volatile int dummy;
+ int i;
+
+ simple_lock_pause_count++;
+
+ /*
+ * Used in loops that are trying to acquire locks out-of-order.
+ */
+
+ for (i = 0; i < simple_lock_pause_loop; i++)
+ dummy++; /* keep the compiler from optimizing the loop away */
+}
+
+#endif /* NCPUS > 1 */
diff --git a/i386/i386/mp_desc.h b/i386/i386/mp_desc.h
new file mode 100644
index 00000000..dbc3f5ea
--- /dev/null
+++ b/i386/i386/mp_desc.h
@@ -0,0 +1,84 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_MP_DESC_H_
+#define _I386_MP_DESC_H_
+
+#include <cpus.h>
+
+#if MULTIPROCESSOR
+
+/*
+ * Multiprocessor i386/i486 systems use a separate copy of the
+ * GDT, IDT, LDT, and kernel TSS per processor. The first three
+ * are separate to avoid lock contention: the i386 uses locked
+ * memory cycles to access the descriptor tables. The TSS is
+ * separate since each processor needs its own kernel stack,
+ * and since using a TSS marks it busy.
+ */
+
+#include "seg.h"
+#include "tss.h"
+#include "idt.h"
+#include "gdt.h"
+#include "ldt.h"
+
+/*
+ * The descriptor tables are together in a structure
+ * allocated one per processor (except for the boot processor).
+ */
+struct mp_desc_table {
+ struct real_gate idt[IDTSZ]; /* IDT */
+ struct real_descriptor gdt[GDTSZ]; /* GDT */
+ struct real_descriptor ldt[LDTSZ]; /* LDT */
+ struct i386_tss ktss;
+};
+
+/*
+ * They are pointed to by a per-processor array.
+ */
+extern struct mp_desc_table *mp_desc_table[NCPUS];
+
+/*
+ * The kernel TSS gets its own pointer.
+ */
+extern struct i386_tss *mp_ktss[NCPUS];
+
+/*
+ * So does the GDT.
+ */
+extern struct real_descriptor *mp_gdt[NCPUS];
+
+
+/*
+ * Each CPU calls this routine to set up its descriptor tables.
+ */
+extern struct mp_desc_table * mp_desc_init(/* int */);
+
+
+#endif MULTIPROCESSOR
+
+#endif /* _I386_MP_DESC_H_ */
diff --git a/i386/i386/pcb.c b/i386/i386/pcb.c
new file mode 100644
index 00000000..f16f21a6
--- /dev/null
+++ b/i386/i386/pcb.c
@@ -0,0 +1,769 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <cpus.h>
+#include <mach_debug.h>
+
+#include <mach/std_types.h>
+#include <mach/kern_return.h>
+#include <mach/thread_status.h>
+#include <mach/exec/exec.h>
+
+#include "vm_param.h"
+#include <kern/counters.h>
+#include <kern/mach_param.h>
+#include <kern/thread.h>
+#include <kern/sched_prim.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+
+#include <i386/thread.h>
+#include <i386/proc_reg.h>
+#include <i386/seg.h>
+#include <i386/tss.h>
+#include <i386/user_ldt.h>
+#include <i386/fpu.h>
+#include "eflags.h"
+#include "gdt.h"
+#include "ldt.h"
+#include "ktss.h"
+
+#if NCPUS > 1
+#include <i386/mp_desc.h>
+#endif
+
+extern thread_t Switch_context();
+extern void Thread_continue();
+
+extern iopb_tss_t iopb_create();
+extern void iopb_destroy();
+extern void user_ldt_free();
+
+zone_t pcb_zone;
+
+vm_offset_t kernel_stack[NCPUS]; /* top of active_stack */
+
+/*
+ * stack_attach:
+ *
+ * Attach a kernel stack to a thread.
+ */
+
+void stack_attach(thread, stack, continuation)
+ register thread_t thread;
+ register vm_offset_t stack;
+ void (*continuation)();
+{
+ counter(if (++c_stacks_current > c_stacks_max)
+ c_stacks_max = c_stacks_current);
+
+ thread->kernel_stack = stack;
+
+ /*
+ * We want to run continuation, giving it as an argument
+ * the return value from Load_context/Switch_context.
+ * Thread_continue takes care of the mismatch between
+ * the argument-passing/return-value conventions.
+ * This function will not return normally,
+ * so we don`t have to worry about a return address.
+ */
+ STACK_IKS(stack)->k_eip = (int) Thread_continue;
+ STACK_IKS(stack)->k_ebx = (int) continuation;
+ STACK_IKS(stack)->k_esp = (int) STACK_IEL(stack);
+
+ /*
+ * Point top of kernel stack to user`s registers.
+ */
+ STACK_IEL(stack)->saved_state = &thread->pcb->iss;
+}
+
+/*
+ * stack_detach:
+ *
+ * Detaches a kernel stack from a thread, returning the old stack.
+ */
+
+vm_offset_t stack_detach(thread)
+ register thread_t thread;
+{
+ register vm_offset_t stack;
+
+ counter(if (--c_stacks_current < c_stacks_min)
+ c_stacks_min = c_stacks_current);
+
+ stack = thread->kernel_stack;
+ thread->kernel_stack = 0;
+
+ return stack;
+}
+
+#if NCPUS > 1
+#define curr_gdt(mycpu) (mp_gdt[mycpu])
+#define curr_ktss(mycpu) (mp_ktss[mycpu])
+#else
+#define curr_gdt(mycpu) (gdt)
+#define curr_ktss(mycpu) (&ktss)
+#endif
+
+#define gdt_desc_p(mycpu,sel) \
+ ((struct real_descriptor *)&curr_gdt(mycpu)[sel_idx(sel)])
+
+void switch_ktss(pcb)
+ register pcb_t pcb;
+{
+ int mycpu = cpu_number();
+ {
+ register iopb_tss_t tss = pcb->ims.io_tss;
+ vm_offset_t pcb_stack_top;
+
+ /*
+ * Save a pointer to the top of the "kernel" stack -
+ * actually the place in the PCB where a trap into
+ * kernel mode will push the registers.
+ * The location depends on V8086 mode. If we are
+ * not in V8086 mode, then a trap into the kernel
+ * won`t save the v86 segments, so we leave room.
+ */
+
+ pcb_stack_top = (pcb->iss.efl & EFL_VM)
+ ? (int) (&pcb->iss + 1)
+ : (int) (&pcb->iss.v86_segs);
+
+ if (tss == 0) {
+ /*
+ * No per-thread IO permissions.
+ * Use standard kernel TSS.
+ */
+ if (!(gdt_desc_p(mycpu,KERNEL_TSS)->access & ACC_TSS_BUSY))
+ set_tr(KERNEL_TSS);
+ curr_ktss(mycpu)->esp0 = pcb_stack_top;
+ }
+ else {
+ /*
+ * Set the IO permissions. Use this thread`s TSS.
+ */
+ *gdt_desc_p(mycpu,USER_TSS)
+ = *(struct real_descriptor *)tss->iopb_desc;
+ tss->tss.esp0 = pcb_stack_top;
+ set_tr(USER_TSS);
+ gdt_desc_p(mycpu,KERNEL_TSS)->access &= ~ ACC_TSS_BUSY;
+ }
+ }
+
+ {
+ register user_ldt_t ldt = pcb->ims.ldt;
+ /*
+ * Set the thread`s LDT.
+ */
+ if (ldt == 0) {
+ /*
+ * Use system LDT.
+ */
+ set_ldt(KERNEL_LDT);
+ }
+ else {
+ /*
+ * Thread has its own LDT.
+ */
+ *gdt_desc_p(mycpu,USER_LDT) = ldt->desc;
+ set_ldt(USER_LDT);
+ }
+ }
+ /*
+ * Load the floating-point context, if necessary.
+ */
+ fpu_load_context(pcb);
+
+}
+
+/*
+ * stack_handoff:
+ *
+ * Move the current thread's kernel stack to the new thread.
+ */
+
+void stack_handoff(old, new)
+ register thread_t old;
+ register thread_t new;
+{
+ register int mycpu = cpu_number();
+ register vm_offset_t stack;
+
+ /*
+ * Save FP registers if in use.
+ */
+ fpu_save_context(old);
+
+ /*
+ * Switch address maps if switching tasks.
+ */
+ {
+ task_t old_task, new_task;
+
+ if ((old_task = old->task) != (new_task = new->task)) {
+ PMAP_DEACTIVATE_USER(vm_map_pmap(old_task->map),
+ old, mycpu);
+ PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map),
+ new, mycpu);
+ }
+ }
+
+ /*
+ * Load the rest of the user state for the new thread
+ */
+ switch_ktss(new->pcb);
+
+ /*
+ * Switch to new thread
+ */
+ stack = current_stack();
+ old->kernel_stack = 0;
+ new->kernel_stack = stack;
+ active_threads[mycpu] = new;
+
+ /*
+ * Switch exception link to point to new
+ * user registers.
+ */
+
+ STACK_IEL(stack)->saved_state = &new->pcb->iss;
+
+}
+
+/*
+ * Switch to the first thread on a CPU.
+ */
+void load_context(new)
+ register thread_t new;
+{
+ switch_ktss(new->pcb);
+ Load_context(new);
+}
+
+/*
+ * Switch to a new thread.
+ * Save the old thread`s kernel state or continuation,
+ * and return it.
+ */
+thread_t switch_context(old, continuation, new)
+ register thread_t old;
+ void (*continuation)();
+ register thread_t new;
+{
+ /*
+ * Save FP registers if in use.
+ */
+ fpu_save_context(old);
+
+ /*
+ * Switch address maps if switching tasks.
+ */
+ {
+ task_t old_task, new_task;
+ int mycpu = cpu_number();
+
+ if ((old_task = old->task) != (new_task = new->task)) {
+ PMAP_DEACTIVATE_USER(vm_map_pmap(old_task->map),
+ old, mycpu);
+ PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map),
+ new, mycpu);
+ }
+ }
+
+ /*
+ * Load the rest of the user state for the new thread
+ */
+ switch_ktss(new->pcb);
+
+ return Switch_context(old, continuation, new);
+}
+
+void pcb_module_init()
+{
+ pcb_zone = zinit(sizeof(struct pcb),
+ THREAD_MAX * sizeof(struct pcb),
+ THREAD_CHUNK * sizeof(struct pcb),
+ 0, "i386 pcb state");
+
+ fpu_module_init();
+ iopb_init();
+}
+
+void pcb_init(thread)
+ register thread_t thread;
+{
+ register pcb_t pcb;
+
+ pcb = (pcb_t) zalloc(pcb_zone);
+ if (pcb == 0)
+ panic("pcb_init");
+
+ counter(if (++c_threads_current > c_threads_max)
+ c_threads_max = c_threads_current);
+
+ /*
+ * We can't let random values leak out to the user.
+ */
+ bzero((char *) pcb, sizeof *pcb);
+ simple_lock_init(&pcb->lock);
+
+ /*
+ * Guarantee that the bootstrapped thread will be in user
+ * mode.
+ */
+ pcb->iss.cs = USER_CS;
+ pcb->iss.ss = USER_DS;
+ pcb->iss.ds = USER_DS;
+ pcb->iss.es = USER_DS;
+ pcb->iss.fs = USER_DS;
+ pcb->iss.gs = USER_DS;
+ pcb->iss.efl = EFL_USER_SET;
+
+ thread->pcb = pcb;
+}
+
+void pcb_terminate(thread)
+ register thread_t thread;
+{
+ register pcb_t pcb = thread->pcb;
+
+ counter(if (--c_threads_current < c_threads_min)
+ c_threads_min = c_threads_current);
+
+ if (pcb->ims.io_tss != 0)
+ iopb_destroy(pcb->ims.io_tss);
+ if (pcb->ims.ifps != 0)
+ fp_free(pcb->ims.ifps);
+ if (pcb->ims.ldt != 0)
+ user_ldt_free(pcb->ims.ldt);
+ zfree(pcb_zone, (vm_offset_t) pcb);
+ thread->pcb = 0;
+}
+
+/*
+ * pcb_collect:
+ *
+ * Attempt to free excess pcb memory.
+ */
+
+void pcb_collect(thread)
+ thread_t thread;
+{
+}
+
+
+/*
+ * thread_setstatus:
+ *
+ * Set the status of the specified thread.
+ */
+
+kern_return_t thread_setstatus(thread, flavor, tstate, count)
+ thread_t thread;
+ int flavor;
+ thread_state_t tstate;
+ unsigned int count;
+{
+ switch (flavor) {
+ case i386_THREAD_STATE:
+ case i386_REGS_SEGS_STATE:
+ {
+ register struct i386_thread_state *state;
+ register struct i386_saved_state *saved_state;
+
+ if (count < i386_THREAD_STATE_COUNT) {
+ return(KERN_INVALID_ARGUMENT);
+ }
+
+ if (flavor == i386_REGS_SEGS_STATE) {
+ /*
+ * Code and stack selectors must not be null,
+ * and must have user protection levels.
+ * Only the low 16 bits are valid.
+ */
+ state->cs &= 0xffff;
+ state->ss &= 0xffff;
+ state->ds &= 0xffff;
+ state->es &= 0xffff;
+ state->fs &= 0xffff;
+ state->gs &= 0xffff;
+
+ if (state->cs == 0 || (state->cs & SEL_PL) != SEL_PL_U
+ || state->ss == 0 || (state->ss & SEL_PL) != SEL_PL_U)
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ state = (struct i386_thread_state *) tstate;
+
+ saved_state = USER_REGS(thread);
+
+ /*
+ * General registers
+ */
+ saved_state->edi = state->edi;
+ saved_state->esi = state->esi;
+ saved_state->ebp = state->ebp;
+ saved_state->uesp = state->uesp;
+ saved_state->ebx = state->ebx;
+ saved_state->edx = state->edx;
+ saved_state->ecx = state->ecx;
+ saved_state->eax = state->eax;
+ saved_state->eip = state->eip;
+ saved_state->efl = (state->efl & ~EFL_USER_CLEAR)
+ | EFL_USER_SET;
+
+ /*
+ * Segment registers. Set differently in V8086 mode.
+ */
+ if (state->efl & EFL_VM) {
+ /*
+ * Set V8086 mode segment registers.
+ */
+ saved_state->cs = state->cs & 0xffff;
+ saved_state->ss = state->ss & 0xffff;
+ saved_state->v86_segs.v86_ds = state->ds & 0xffff;
+ saved_state->v86_segs.v86_es = state->es & 0xffff;
+ saved_state->v86_segs.v86_fs = state->fs & 0xffff;
+ saved_state->v86_segs.v86_gs = state->gs & 0xffff;
+
+ /*
+ * Zero protected mode segment registers.
+ */
+ saved_state->ds = 0;
+ saved_state->es = 0;
+ saved_state->fs = 0;
+ saved_state->gs = 0;
+
+ if (thread->pcb->ims.v86s.int_table) {
+ /*
+ * Hardware assist on.
+ */
+ thread->pcb->ims.v86s.flags =
+ state->efl & (EFL_TF | EFL_IF);
+ }
+ }
+ else if (flavor == i386_THREAD_STATE) {
+ /*
+ * 386 mode. Set segment registers for flat
+ * 32-bit address space.
+ */
+ saved_state->cs = USER_CS;
+ saved_state->ss = USER_DS;
+ saved_state->ds = USER_DS;
+ saved_state->es = USER_DS;
+ saved_state->fs = USER_DS;
+ saved_state->gs = USER_DS;
+ }
+ else {
+ /*
+ * User setting segment registers.
+ * Code and stack selectors have already been
+ * checked. Others will be reset by 'iret'
+ * if they are not valid.
+ */
+ saved_state->cs = state->cs;
+ saved_state->ss = state->ss;
+ saved_state->ds = state->ds;
+ saved_state->es = state->es;
+ saved_state->fs = state->fs;
+ saved_state->gs = state->gs;
+ }
+ break;
+ }
+
+ case i386_FLOAT_STATE: {
+
+ if (count < i386_FLOAT_STATE_COUNT)
+ return(KERN_INVALID_ARGUMENT);
+
+ return fpu_set_state(thread,
+ (struct i386_float_state *) tstate);
+ }
+
+ /*
+ * Temporary - replace by i386_io_map
+ */
+ case i386_ISA_PORT_MAP_STATE: {
+ register struct i386_isa_port_map_state *state;
+ register iopb_tss_t tss;
+
+ if (count < i386_ISA_PORT_MAP_STATE_COUNT)
+ return(KERN_INVALID_ARGUMENT);
+
+#if 0
+ /*
+ * If the thread has no ktss yet,
+ * we must allocate one.
+ */
+
+ state = (struct i386_isa_port_map_state *) tstate;
+ tss = thread->pcb->ims.io_tss;
+ if (tss == 0) {
+ tss = iopb_create();
+ thread->pcb->ims.io_tss = tss;
+ }
+
+ bcopy((char *) state->pm,
+ (char *) tss->bitmap,
+ sizeof state->pm);
+#endif
+ break;
+ }
+
+ case i386_V86_ASSIST_STATE:
+ {
+ register struct i386_v86_assist_state *state;
+ vm_offset_t int_table;
+ int int_count;
+
+ if (count < i386_V86_ASSIST_STATE_COUNT)
+ return KERN_INVALID_ARGUMENT;
+
+ state = (struct i386_v86_assist_state *) tstate;
+ int_table = state->int_table;
+ int_count = state->int_count;
+
+ if (int_table >= VM_MAX_ADDRESS ||
+ int_table +
+ int_count * sizeof(struct v86_interrupt_table)
+ > VM_MAX_ADDRESS)
+ return KERN_INVALID_ARGUMENT;
+
+ thread->pcb->ims.v86s.int_table = int_table;
+ thread->pcb->ims.v86s.int_count = int_count;
+
+ thread->pcb->ims.v86s.flags =
+ USER_REGS(thread)->efl & (EFL_TF | EFL_IF);
+ break;
+ }
+
+ default:
+ return(KERN_INVALID_ARGUMENT);
+ }
+
+ return(KERN_SUCCESS);
+}
+
+/*
+ * thread_getstatus:
+ *
+ * Get the status of the specified thread.
+ */
+
+kern_return_t thread_getstatus(thread, flavor, tstate, count)
+ register thread_t thread;
+ int flavor;
+ thread_state_t tstate; /* pointer to OUT array */
+ unsigned int *count; /* IN/OUT */
+{
+ switch (flavor) {
+ case THREAD_STATE_FLAVOR_LIST:
+ if (*count < 4)
+ return (KERN_INVALID_ARGUMENT);
+ tstate[0] = i386_THREAD_STATE;
+ tstate[1] = i386_FLOAT_STATE;
+ tstate[2] = i386_ISA_PORT_MAP_STATE;
+ tstate[3] = i386_V86_ASSIST_STATE;
+ *count = 4;
+ break;
+
+ case i386_THREAD_STATE:
+ case i386_REGS_SEGS_STATE:
+ {
+ register struct i386_thread_state *state;
+ register struct i386_saved_state *saved_state;
+
+ if (*count < i386_THREAD_STATE_COUNT)
+ return(KERN_INVALID_ARGUMENT);
+
+ state = (struct i386_thread_state *) tstate;
+ saved_state = USER_REGS(thread);
+
+ /*
+ * General registers.
+ */
+ state->edi = saved_state->edi;
+ state->esi = saved_state->esi;
+ state->ebp = saved_state->ebp;
+ state->ebx = saved_state->ebx;
+ state->edx = saved_state->edx;
+ state->ecx = saved_state->ecx;
+ state->eax = saved_state->eax;
+ state->eip = saved_state->eip;
+ state->efl = saved_state->efl;
+ state->uesp = saved_state->uesp;
+
+ state->cs = saved_state->cs;
+ state->ss = saved_state->ss;
+ if (saved_state->efl & EFL_VM) {
+ /*
+ * V8086 mode.
+ */
+ state->ds = saved_state->v86_segs.v86_ds & 0xffff;
+ state->es = saved_state->v86_segs.v86_es & 0xffff;
+ state->fs = saved_state->v86_segs.v86_fs & 0xffff;
+ state->gs = saved_state->v86_segs.v86_gs & 0xffff;
+
+ if (thread->pcb->ims.v86s.int_table) {
+ /*
+ * Hardware assist on
+ */
+ if ((thread->pcb->ims.v86s.flags &
+ (EFL_IF|V86_IF_PENDING))
+ == 0)
+ state->efl &= ~EFL_IF;
+ }
+ }
+ else {
+ /*
+ * 386 mode.
+ */
+ state->ds = saved_state->ds & 0xffff;
+ state->es = saved_state->es & 0xffff;
+ state->fs = saved_state->fs & 0xffff;
+ state->gs = saved_state->gs & 0xffff;
+ }
+ *count = i386_THREAD_STATE_COUNT;
+ break;
+ }
+
+ case i386_FLOAT_STATE: {
+
+ if (*count < i386_FLOAT_STATE_COUNT)
+ return(KERN_INVALID_ARGUMENT);
+
+ *count = i386_FLOAT_STATE_COUNT;
+ return fpu_get_state(thread,
+ (struct i386_float_state *)tstate);
+ }
+
+ /*
+ * Temporary - replace by i386_io_map
+ */
+ case i386_ISA_PORT_MAP_STATE: {
+ register struct i386_isa_port_map_state *state;
+ register iopb_tss_t tss;
+
+ if (*count < i386_ISA_PORT_MAP_STATE_COUNT)
+ return(KERN_INVALID_ARGUMENT);
+
+ state = (struct i386_isa_port_map_state *) tstate;
+ tss = thread->pcb->ims.io_tss;
+
+ if (tss == 0) {
+ int i;
+
+ /*
+ * The thread has no ktss, so no IO permissions.
+ */
+
+ for (i = 0; i < sizeof state->pm; i++)
+ state->pm[i] = 0xff;
+ } else {
+ /*
+ * The thread has its own ktss.
+ */
+
+ bcopy((char *) tss->bitmap,
+ (char *) state->pm,
+ sizeof state->pm);
+ }
+
+ *count = i386_ISA_PORT_MAP_STATE_COUNT;
+ break;
+ }
+
+ case i386_V86_ASSIST_STATE:
+ {
+ register struct i386_v86_assist_state *state;
+
+ if (*count < i386_V86_ASSIST_STATE_COUNT)
+ return KERN_INVALID_ARGUMENT;
+
+ state = (struct i386_v86_assist_state *) tstate;
+ state->int_table = thread->pcb->ims.v86s.int_table;
+ state->int_count = thread->pcb->ims.v86s.int_count;
+
+ *count = i386_V86_ASSIST_STATE_COUNT;
+ break;
+ }
+
+ default:
+ return(KERN_INVALID_ARGUMENT);
+ }
+
+ return(KERN_SUCCESS);
+}
+
+/*
+ * Alter the thread`s state so that a following thread_exception_return
+ * will make the thread return 'retval' from a syscall.
+ */
+void
+thread_set_syscall_return(thread, retval)
+ thread_t thread;
+ kern_return_t retval;
+{
+ thread->pcb->iss.eax = retval;
+}
+
+
+/*
+ * Return prefered address of user stack.
+ * Always returns low address. If stack grows up,
+ * the stack grows away from this address;
+ * if stack grows down, the stack grows towards this
+ * address.
+ */
+vm_offset_t
+user_stack_low(stack_size)
+ vm_size_t stack_size;
+{
+ return (VM_MAX_ADDRESS - stack_size);
+}
+
+/*
+ * Allocate argument area and set registers for first user thread.
+ */
+vm_offset_t
+set_user_regs(stack_base, stack_size, exec_info, arg_size)
+ vm_offset_t stack_base; /* low address */
+ vm_offset_t stack_size;
+ struct exec_info *exec_info;
+ vm_size_t arg_size;
+{
+ vm_offset_t arg_addr;
+ register struct i386_saved_state *saved_state;
+
+ arg_size = (arg_size + sizeof(int) - 1) & ~(sizeof(int)-1);
+ arg_addr = stack_base + stack_size - arg_size;
+
+ saved_state = USER_REGS(current_thread());
+ saved_state->uesp = (int)arg_addr;
+ saved_state->eip = exec_info->entry;
+
+ return (arg_addr);
+}
diff --git a/i386/i386/phys.c b/i386/i386/phys.c
new file mode 100644
index 00000000..518812d3
--- /dev/null
+++ b/i386/i386/phys.c
@@ -0,0 +1,102 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <mach/boolean.h>
+#include <kern/task.h>
+#include <kern/thread.h>
+#include <vm/vm_map.h>
+#include "vm_param.h"
+#include <mach/vm_prot.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+
+#include <i386/pmap.h>
+#include <mach/machine/vm_param.h>
+
+/*
+ * pmap_zero_page zeros the specified (machine independent) page.
+ */
+pmap_zero_page(p)
+ vm_offset_t p;
+{
+ assert(p != vm_page_fictitious_addr);
+ bzero(phystokv(p), PAGE_SIZE);
+}
+
+/*
+ * pmap_copy_page copies the specified (machine independent) pages.
+ */
+pmap_copy_page(src, dst)
+ vm_offset_t src, dst;
+{
+ assert(src != vm_page_fictitious_addr);
+ assert(dst != vm_page_fictitious_addr);
+
+ bcopy(phystokv(src), phystokv(dst), PAGE_SIZE);
+}
+
+/*
+ * copy_to_phys(src_addr_v, dst_addr_p, count)
+ *
+ * Copy virtual memory to physical memory
+ */
+copy_to_phys(src_addr_v, dst_addr_p, count)
+ vm_offset_t src_addr_v, dst_addr_p;
+ int count;
+{
+ assert(dst_addr_p != vm_page_fictitious_addr);
+ bcopy(src_addr_v, phystokv(dst_addr_p), count);
+}
+
+/*
+ * copy_from_phys(src_addr_p, dst_addr_v, count)
+ *
+ * Copy physical memory to virtual memory. The virtual memory
+ * is assumed to be present (e.g. the buffer pool).
+ */
+copy_from_phys(src_addr_p, dst_addr_v, count)
+ vm_offset_t src_addr_p, dst_addr_v;
+ int count;
+{
+ assert(src_addr_p != vm_page_fictitious_addr);
+ bcopy(phystokv(src_addr_p), dst_addr_v, count);
+}
+
+/*
+ * kvtophys(addr)
+ *
+ * Convert a kernel virtual address to a physical address
+ */
+vm_offset_t
+kvtophys(addr)
+vm_offset_t addr;
+{
+ pt_entry_t *pte;
+
+ if ((pte = pmap_pte(kernel_pmap, addr)) == PT_ENTRY_NULL)
+ return 0;
+ return i386_trunc_page(*pte) | (addr & INTEL_OFFMASK);
+}
diff --git a/i386/i386/pic.c b/i386/i386/pic.c
new file mode 100644
index 00000000..8380db84
--- /dev/null
+++ b/i386/i386/pic.c
@@ -0,0 +1,270 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+Copyright (c) 1988,1989 Prime Computer, Inc. Natick, MA 01760
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this
+software and its documentation for any purpose and
+without fee is hereby granted, provided that the above
+copyright notice appears in all copies and that both the
+copyright notice and this permission notice appear in
+supporting documentation, and that the name of Prime
+Computer, Inc. not be used in advertising or publicity
+pertaining to distribution of the software without
+specific, written prior permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS", AND PRIME COMPUTER,
+INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN
+NO EVENT SHALL PRIME COMPUTER, INC. BE LIABLE FOR ANY
+SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN ACTION OF CONTRACT, NEGLIGENCE, OR
+OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <platforms.h>
+
+#include <sys/types.h>
+#include <i386/ipl.h>
+#include <i386/pic.h>
+#include <i386/machspl.h>
+
+spl_t curr_ipl;
+int pic_mask[NSPL];
+int curr_pic_mask;
+
+int iunit[NINTR] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+
+int nintr = NINTR;
+int npics = NPICS;
+
+char *master_icw, *master_ocw, *slaves_icw, *slaves_ocw;
+
+u_short PICM_ICW1, PICM_OCW1, PICS_ICW1, PICS_OCW1 ;
+u_short PICM_ICW2, PICM_OCW2, PICS_ICW2, PICS_OCW2 ;
+u_short PICM_ICW3, PICM_OCW3, PICS_ICW3, PICS_OCW3 ;
+u_short PICM_ICW4, PICS_ICW4 ;
+
+/*
+** picinit() - This routine
+** * Establishes a table of interrupt vectors
+** * Establishes a table of interrupt priority levels
+** * Establishes a table of interrupt masks to be put
+** in the PICs.
+** * Establishes location of PICs in the system
+** * Initialises them
+**
+** At this stage the interrupt functionality of this system should be
+** coplete.
+**
+*/
+
+
+/*
+** 1. First we form a table of PIC masks - rather then calling form_pic_mask()
+** each time there is a change of interrupt level - we will form a table
+** of pic masks, as there are only 7 interrupt priority levels.
+**
+** 2. The next thing we must do is to determine which of the PIC interrupt
+** request lines have to be masked out, this is done by calling
+** form_pic_mask() with a (int_lev) of zero, this will find all the
+** interrupt lines that have priority 0, (ie to be ignored).
+** Then we split this up for the master/slave PICs.
+**
+** 2. Initialise the PICs , master first, then the slave.
+** All the register field definitions are described in pic_jh.h, also
+** the settings of these fields for the various registers are selected.
+**
+*/
+
+picinit()
+{
+
+ u_short i;
+
+ asm("cli");
+
+ /*
+ ** 1. Form pic mask table
+ */
+#if 0
+ printf (" Let the console driver screw up this line ! \n");
+#endif
+
+ form_pic_mask();
+
+ /*
+ ** 1a. Select current SPL.
+ */
+
+ curr_ipl = SPLHI;
+ curr_pic_mask = pic_mask[SPLHI];
+
+ /*
+ ** 2. Generate addresses to each PIC port.
+ */
+
+ master_icw = (char *)PIC_MASTER_ICW;
+ master_ocw = (char *)PIC_MASTER_OCW;
+ slaves_icw = (char *)PIC_SLAVE_ICW;
+ slaves_ocw = (char *)PIC_SLAVE_OCW;
+
+#ifdef PS2
+#else /* PS2 */
+ /*
+ ** 3. Select options for each ICW and each OCW for each PIC.
+ */
+
+ PICM_ICW1 =
+ (ICW_TEMPLATE | EDGE_TRIGGER | ADDR_INTRVL8 | CASCADE_MODE | ICW4__NEEDED);
+
+ PICS_ICW1 =
+ (ICW_TEMPLATE | EDGE_TRIGGER | ADDR_INTRVL8 | CASCADE_MODE | ICW4__NEEDED);
+
+ PICM_ICW2 = PICM_VECTBASE;
+ PICS_ICW2 = PICS_VECTBASE;
+
+#ifdef AT386
+ PICM_ICW3 = ( SLAVE_ON_IR2 );
+ PICS_ICW3 = ( I_AM_SLAVE_2 );
+#endif AT386
+#ifdef iPSC386
+ PICM_ICW3 = ( SLAVE_ON_IR7 );
+ PICS_ICW3 = ( I_AM_SLAVE_7 );
+#endif iPSC386
+
+#ifdef iPSC386
+ /* Use Buffered mode for iPSC386 */
+ PICM_ICW4 = (SNF_MODE_DIS | BUFFERD_MODE | I_AM_A_MASTR |
+ NRML_EOI_MOD | I8086_EMM_MOD);
+ PICS_ICW4 = (SNF_MODE_DIS | BUFFERD_MODE | I_AM_A_SLAVE |
+ NRML_EOI_MOD | I8086_EMM_MOD);
+#else iPSC386
+ PICM_ICW4 =
+ (SNF_MODE_DIS | NONBUFD_MODE | NRML_EOI_MOD | I8086_EMM_MOD);
+ PICS_ICW4 =
+ (SNF_MODE_DIS | NONBUFD_MODE | NRML_EOI_MOD | I8086_EMM_MOD);
+#endif iPSC386
+
+ PICM_OCW1 = (curr_pic_mask & 0x00FF);
+ PICS_OCW1 = ((curr_pic_mask & 0xFF00)>>8);
+
+ PICM_OCW2 = NON_SPEC_EOI;
+ PICS_OCW2 = NON_SPEC_EOI;
+
+ PICM_OCW3 = (OCW_TEMPLATE | READ_NEXT_RD | READ_IR_ONRD );
+ PICS_OCW3 = (OCW_TEMPLATE | READ_NEXT_RD | READ_IR_ONRD );
+
+
+ /*
+ ** 4. Initialise master - send commands to master PIC
+ */
+
+ outb ( master_icw, PICM_ICW1 );
+ outb ( master_ocw, PICM_ICW2 );
+ outb ( master_ocw, PICM_ICW3 );
+ outb ( master_ocw, PICM_ICW4 );
+
+ outb ( master_ocw, PICM_MASK );
+ outb ( master_icw, PICM_OCW3 );
+
+ /*
+ ** 5. Initialise slave - send commands to slave PIC
+ */
+
+ outb ( slaves_icw, PICS_ICW1 );
+ outb ( slaves_ocw, PICS_ICW2 );
+ outb ( slaves_ocw, PICS_ICW3 );
+ outb ( slaves_ocw, PICS_ICW4 );
+
+
+ outb ( slaves_ocw, PICS_OCW1 );
+ outb ( slaves_icw, PICS_OCW3 );
+
+ /*
+ ** 6. Initialise interrupts
+ */
+ outb ( master_ocw, PICM_OCW1 );
+
+#endif /* PS2 */
+
+#if 0
+ printf(" spl set to %x \n", curr_pic_mask);
+#endif
+
+}
+
+
+/*
+** form_pic_mask(int_lvl)
+**
+** For a given interrupt priority level (int_lvl), this routine goes out
+** and scans through the interrupt level table, and forms a mask based on the
+** entries it finds there that have the same or lower interrupt priority level
+** as (int_lvl). It returns a 16-bit mask which will have to be split up between
+** the 2 pics.
+**
+*/
+
+#if defined(AT386) || defined(PS2)
+#define SLAVEMASK (0xFFFF ^ SLAVE_ON_IR2)
+#endif /* defined(AT386) || defined(PS2) */
+#ifdef iPSC386
+#define SLAVEMASK (0xFFFF ^ SLAVE_ON_IR7)
+#endif iPSC386
+
+#define SLAVEACTV 0xFF00
+
+form_pic_mask()
+{
+ unsigned int i, j, bit, mask;
+
+ for (i=SPL0; i < NSPL; i++) {
+ for (j=0x00, bit=0x01, mask = 0; j < NINTR; j++, bit<<=1)
+ if (intpri[j] <= i)
+ mask |= bit;
+
+ if ((mask & SLAVEACTV) != SLAVEACTV )
+ mask &= SLAVEMASK;
+
+ pic_mask[i] = mask;
+ }
+}
+
+intnull(unit_dev)
+{
+ printf("intnull(%d)\n", unit_dev);
+}
+
+int prtnull_count = 0;
+prtnull(unit)
+{
+ ++prtnull_count;
+}
diff --git a/i386/i386/pic.h b/i386/i386/pic.h
new file mode 100644
index 00000000..66b92d80
--- /dev/null
+++ b/i386/i386/pic.h
@@ -0,0 +1,197 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+Copyright (c) 1988,1989 Prime Computer, Inc. Natick, MA 01760
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this
+software and its documentation for any purpose and
+without fee is hereby granted, provided that the above
+copyright notice appears in all copies and that both the
+copyright notice and this permission notice appear in
+supporting documentation, and that the name of Prime
+Computer, Inc. not be used in advertising or publicity
+pertaining to distribution of the software without
+specific, written prior permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS", AND PRIME COMPUTER,
+INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN
+NO EVENT SHALL PRIME COMPUTER, INC. BE LIABLE FOR ANY
+SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN ACTION OF CONTRACT, NEGLIGENCE, OR
+OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef _I386_PIC_H_
+#define _I386_PIC_H_
+
+#include <platforms.h>
+
+#define NINTR 0x10
+#define NPICS 0x02
+
+/*
+** The following are definitions used to locate the PICs in the system
+*/
+
+#if defined(AT386) || defined(PS2)
+#define ADDR_PIC_BASE 0x20
+#define OFF_ICW 0x00
+#define OFF_OCW 0x01
+#define SIZE_PIC 0x80
+#endif /* defined(AT386) || defined(PS2) */
+
+#ifdef iPSC386
+#define ADDR_PIC_BASE 0xC0
+#define OFF_ICW 0x00
+#define OFF_OCW 0x02
+#define SIZE_PIC 0x04
+#endif iPSC386
+
+#define PIC_MASTER_ICW (ADDR_PIC_BASE + OFF_ICW)
+#define PIC_MASTER_OCW (ADDR_PIC_BASE + OFF_OCW)
+#define PIC_SLAVE_ICW (PIC_MASTER_ICW + SIZE_PIC)
+#define PIC_SLAVE_OCW (PIC_MASTER_OCW + SIZE_PIC)
+
+/*
+** The following banks of definitions ICW1, ICW2, ICW3, and ICW4 are used
+** to define the fields of the various ICWs for initialisation of the PICs
+*/
+
+/*
+** ICW1
+*/
+
+#define ICW_TEMPLATE 0x10
+
+#define LEVL_TRIGGER 0x08
+#define EDGE_TRIGGER 0x00
+#define ADDR_INTRVL4 0x04
+#define ADDR_INTRVL8 0x00
+#define SINGLE__MODE 0x02
+#define CASCADE_MODE 0x00
+#define ICW4__NEEDED 0x01
+#define NO_ICW4_NEED 0x00
+
+/*
+** ICW2
+*/
+
+#if defined(AT386) || defined(PS2)
+#define PICM_VECTBASE 0x40
+#define PICS_VECTBASE PICM_VECTBASE + 0x08
+#endif /* defined(AT386) || defined(PS2) */
+
+#ifdef iPSC386
+#define PICM_VECTBASE 0x40
+#define PICS_VECTBASE PICM_VECTBASE + 0x08
+#endif iPSC386
+
+/*
+** ICW3
+*/
+
+#define SLAVE_ON_IR0 0x01
+#define SLAVE_ON_IR1 0x02
+#define SLAVE_ON_IR2 0x04
+#define SLAVE_ON_IR3 0x08
+#define SLAVE_ON_IR4 0x10
+#define SLAVE_ON_IR5 0x20
+#define SLAVE_ON_IR6 0x40
+#define SLAVE_ON_IR7 0x80
+
+#define I_AM_SLAVE_0 0x00
+#define I_AM_SLAVE_1 0x01
+#define I_AM_SLAVE_2 0x02
+#define I_AM_SLAVE_3 0x03
+#define I_AM_SLAVE_4 0x04
+#define I_AM_SLAVE_5 0x05
+#define I_AM_SLAVE_6 0x06
+#define I_AM_SLAVE_7 0x07
+
+/*
+** ICW4
+*/
+
+#define SNF_MODE_ENA 0x10
+#define SNF_MODE_DIS 0x00
+#define BUFFERD_MODE 0x08
+#define NONBUFD_MODE 0x00
+#if iPSC386
+#define I_AM_A_SLAVE 0x00
+#define I_AM_A_MASTR 0x04
+#endif iPSC386
+#define AUTO_EOI_MOD 0x02
+#define NRML_EOI_MOD 0x00
+#define I8086_EMM_MOD 0x01
+#define SET_MCS_MODE 0x00
+
+/*
+** OCW1
+*/
+#define PICM_MASK 0xFF
+#define PICS_MASK 0xFF
+/*
+** OCW2
+*/
+
+#define NON_SPEC_EOI 0x20
+#define SPECIFIC_EOI 0x30
+#define ROT_NON_SPEC 0x50
+#define SET_ROT_AEOI 0x40
+#define RSET_ROTAEOI 0x00
+#define ROT_SPEC_EOI 0x70
+#define SET_PRIORITY 0x60
+#define NO_OPERATION 0x20
+
+#define SEND_EOI_IR0 0x00
+#define SEND_EOI_IR1 0x01
+#define SEND_EOI_IR2 0x02
+#define SEND_EOI_IR3 0x03
+#define SEND_EOI_IR4 0x04
+#define SEND_EOI_IR5 0x05
+#define SEND_EOI_IR6 0x06
+#define SEND_EOI_IR7 0x07
+
+/*
+** OCW3
+*/
+
+#define OCW_TEMPLATE 0x08
+#define SPECIAL_MASK 0x40
+#define MASK_MDE_SET 0x20
+#define MASK_MDE_RST 0x00
+#define POLL_COMMAND 0x04
+#define NO_POLL_CMND 0x00
+#define READ_NEXT_RD 0x02
+#define READ_IR_ONRD 0x00
+#define READ_IS_ONRD 0x01
+
+#endif _I386_PIC_H_
diff --git a/i386/i386/pio.h b/i386/i386/pio.h
new file mode 100644
index 00000000..b2427f92
--- /dev/null
+++ b/i386/i386/pio.h
@@ -0,0 +1,61 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_PIO_H_
+#define _I386_PIO_H_
+
+#ifndef __GNUC__
+#error You do not stand a chance. This file is gcc only.
+#endif __GNUC__
+
+#define inl(y) \
+({ unsigned long _tmp__; \
+ asm volatile("inl %1, %0" : "=a" (_tmp__) : "d" ((unsigned short)(y))); \
+ _tmp__; })
+
+#define inw(y) \
+({ unsigned short _tmp__; \
+ asm volatile(".byte 0x66; inl %1, %0" : "=a" (_tmp__) : "d" ((unsigned short)(y))); \
+ _tmp__; })
+
+#define inb(y) \
+({ unsigned char _tmp__; \
+ asm volatile("inb %1, %0" : "=a" (_tmp__) : "d" ((unsigned short)(y))); \
+ _tmp__; })
+
+
+#define outl(x, y) \
+{ asm volatile("outl %0, %1" : : "a" (y) , "d" ((unsigned short)(x))); }
+
+
+#define outw(x, y) \
+{asm volatile(".byte 0x66; outl %0, %1" : : "a" ((unsigned short)(y)) , "d" ((unsigned short)(x))); }
+
+
+#define outb(x, y) \
+{ asm volatile("outb %0, %1" : : "a" ((unsigned char)(y)) , "d" ((unsigned short)(x))); }
+
+#endif /* _I386_PIO_H_ */
diff --git a/i386/i386/pit.c b/i386/i386/pit.c
new file mode 100644
index 00000000..3ae14870
--- /dev/null
+++ b/i386/i386/pit.c
@@ -0,0 +1,236 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * Copyright (c) 1991 IBM Corporation
+ * 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,
+ * and that the name IBM not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written
+ * prior permission.
+ *
+ * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <platforms.h>
+#include <kern/time_out.h>
+#include <i386/ipl.h>
+#include <i386/pit.h>
+
+int pitctl_port = PITCTL_PORT; /* For 386/20 Board */
+int pitctr0_port = PITCTR0_PORT; /* For 386/20 Board */
+int pitctr1_port = PITCTR1_PORT; /* For 386/20 Board */
+int pitctr2_port = PITCTR2_PORT; /* For 386/20 Board */
+/* We want PIT 0 in square wave mode */
+
+int pit0_mode = PIT_C0|PIT_SQUAREMODE|PIT_READMODE ;
+
+
+unsigned int delaycount; /* loop count in trying to delay for
+ * 1 millisecond
+ */
+unsigned long microdata=50; /* loop count for 10 microsecond wait.
+ MUST be initialized for those who
+ insist on calling "tenmicrosec"
+ it before the clock has been
+ initialized.
+ */
+unsigned int clknumb = CLKNUM; /* interrupt interval for timer 0 */
+
+#ifdef PS2
+extern int clock_int_handler();
+
+#include <sys/types.h>
+#include <i386ps2/abios.h>
+static struct generic_request *clock_request_block;
+static int clock_flags;
+char cqbuf[200]; /*XXX temporary.. should use kmem_alloc or whatever..*/
+#endif /* PS2 */
+
+clkstart()
+{
+ unsigned int flags;
+ unsigned char byte;
+ int s;
+
+ intpri[0] = SPLHI;
+ form_pic_mask();
+
+ findspeed();
+ microfind();
+ s = sploff(); /* disable interrupts */
+
+#ifdef PS2
+ abios_clock_start();
+#endif /* PS2 */
+
+ /* Since we use only timer 0, we program that.
+ * 8254 Manual specifically says you do not need to program
+ * timers you do not use
+ */
+ outb(pitctl_port, pit0_mode);
+ clknumb = CLKNUM/hz;
+ byte = clknumb;
+ outb(pitctr0_port, byte);
+ byte = clknumb>>8;
+ outb(pitctr0_port, byte);
+ splon(s); /* restore interrupt state */
+}
+
+#define COUNT 10000 /* should be a multiple of 1000! */
+
+findspeed()
+{
+ unsigned int flags;
+ unsigned char byte;
+ unsigned int leftover;
+ int i;
+ int j;
+ int s;
+
+ s = sploff(); /* disable interrupts */
+ /* Put counter in count down mode */
+#define PIT_COUNTDOWN PIT_READMODE|PIT_NDIVMODE
+ outb(pitctl_port, PIT_COUNTDOWN);
+ /* output a count of -1 to counter 0 */
+ outb(pitctr0_port, 0xff);
+ outb(pitctr0_port, 0xff);
+ delaycount = COUNT;
+ spinwait(1);
+ /* Read the value left in the counter */
+ byte = inb(pitctr0_port); /* least siginifcant */
+ leftover = inb(pitctr0_port); /* most significant */
+ leftover = (leftover<<8) + byte ;
+ /* Formula for delaycount is :
+ * (loopcount * timer clock speed)/ (counter ticks * 1000)
+ * 1000 is for figuring out milliseconds
+ */
+ /* we arrange calculation so that it doesn't overflow */
+ delaycount = ((COUNT/1000) * CLKNUM) / (0xffff-leftover);
+ printf("findspeed: delaycount=%d (tics=%d)\n",
+ delaycount, (0xffff-leftover));
+ splon(s); /* restore interrupt state */
+}
+
+#ifdef PS2
+
+abios_clock_start()
+{
+ struct generic_request temp_request_block;
+ int rc;
+
+ nmi_enable(); /* has to happen somewhere! */
+ temp_request_block.r_current_req_blck_len = ABIOS_MIN_REQ_SIZE;
+ temp_request_block.r_logical_id = abios_next_LID(SYSTIME_ID,
+ ABIOS_FIRST_LID);
+ temp_request_block.r_unit = 0;
+ temp_request_block.r_function = ABIOS_LOGICAL_PARAMETER;
+ temp_request_block.r_return_code = ABIOS_UNDEFINED;
+
+ abios_common_start(&temp_request_block,0);
+ if (temp_request_block.r_return_code != ABIOS_DONE) {
+ panic("couldn init abios time code!\n");
+ }
+
+ /*
+ * now build the clock request for the hardware system clock
+ */
+ clock_request_block = (struct generic_request *)cqbuf;
+ clock_request_block->r_current_req_blck_len =
+ temp_request_block.r_request_block_length;
+ clock_request_block->r_logical_id = temp_request_block.r_logical_id;
+ clock_request_block->r_unit = 0;
+ clock_request_block->r_function = ABIOS_DEFAULT_INTERRUPT;
+ clock_request_block->r_return_code = ABIOS_UNDEFINED;
+ clock_flags = temp_request_block.r_logical_id_flags;
+}
+
+ackrtclock()
+{
+ if (clock_request_block) {
+ clock_request_block->r_return_code = ABIOS_UNDEFINED;
+ abios_common_interrupt(clock_request_block,clock_flags);
+ }
+ }
+#endif /* PS2 */
+
+
+spinwait(millis)
+ int millis; /* number of milliseconds to delay */
+{
+ int i, j;
+
+ for (i=0;i<millis;i++)
+ for (j=0;j<delaycount;j++)
+ ;
+}
+
+#define MICROCOUNT 1000 /* keep small to prevent overflow */
+microfind()
+{
+ unsigned int flags;
+ unsigned char byte;
+ unsigned short leftover;
+ int s;
+
+
+ s = sploff(); /* disable interrupts */
+
+ /* Put counter in count down mode */
+ outb(pitctl_port, PIT_COUNTDOWN);
+ /* output a count of -1 to counter 0 */
+ outb(pitctr0_port, 0xff);
+ outb(pitctr0_port, 0xff);
+ microdata=MICROCOUNT;
+ tenmicrosec();
+ /* Read the value left in the counter */
+ byte = inb(pitctr0_port); /* least siginifcant */
+ leftover = inb(pitctr0_port); /* most significant */
+ leftover = (leftover<<8) + byte ;
+ /* Formula for delaycount is :
+ * (loopcount * timer clock speed)/ (counter ticks * 1000)
+ * Note also that 1000 is for figuring out milliseconds
+ */
+ microdata = (MICROCOUNT * CLKNUM) / ((0xffff-leftover)*100000);
+ if (!microdata)
+ microdata++;
+
+ splon(s); /* restore interrupt state */
+}
diff --git a/i386/i386/pit.h b/i386/i386/pit.h
new file mode 100644
index 00000000..3cadb30a
--- /dev/null
+++ b/i386/i386/pit.h
@@ -0,0 +1,118 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <platforms.h>
+#if defined(MB1) || defined(MB2) || EXL > 0 || iPSC386
+/* Definitions for 8254 Programmable Interrupt Timer ports on 386/20 */
+#define PITCTR0_PORT 0xD0 /* counter 0 port */
+#define PITCTR1_PORT 0xD2 /* counter 1 port */
+#define PITCTR2_PORT 0xD4 /* counter 2 port */
+#define PITCTL_PORT 0xD6 /* PIT control port */
+#else /* defined(AT386) || defined(PS2) */
+/* Definitions for 8254 Programmable Interrupt Timer ports on AT 386 */
+#define PITCTR0_PORT 0x40 /* counter 0 port */
+#define PITCTR1_PORT 0x41 /* counter 1 port */
+#define PITCTR2_PORT 0x42 /* counter 2 port */
+#define PITCTL_PORT 0x43 /* PIT control port */
+#define PITAUX_PORT 0x61 /* PIT auxiliary port */
+/* bits used in auxiliary control port for timer 2 */
+#define PITAUX_GATE2 0x01 /* aux port, PIT gate 2 input */
+#define PITAUX_OUT2 0x02 /* aux port, PIT clock out 2 enable */
+#endif /* defined(AT386) || defined(PS2) */
+
+/* Following are used for Timer 0 */
+#define PIT_C0 0x00 /* select counter 0 */
+#define PIT_LOADMODE 0x30 /* load least significant byte followed
+ * by most significant byte */
+#define PIT_NDIVMODE 0x04 /*divide by N counter */
+#define PIT_SQUAREMODE 0x06 /* square-wave mode */
+
+/* Used for Timer 1. Used for delay calculations in countdown mode */
+#define PIT_C1 0x40 /* select counter 1 */
+#define PIT_READMODE 0x30 /* read or load least significant byte
+ * followed by most significant byte */
+#define PIT_RATEMODE 0x06 /* square-wave mode for USART */
+
+/*
+ * Clock speed for the timer in hz divided by the constant HZ
+ * (defined in param.h)
+ */
+#if AT386 || PS2
+#define CLKNUM 1193167
+#endif /* AT386 || PS2 */
+#if defined(MB1)
+#define CLKNUM 12300
+#endif
+#if defined(MB2) || EXL > 0
+#define CLKNUM 12500
+#endif
+#if iPSC386
+#define CLKNUM 1000000
+#endif iPSC386
+
+#if EXL
+/* added micro-timer support. --- csy */
+typedef struct time_latch {
+ time_t ticks; /* time in HZ since boot */
+ time_t uticks; /* time in 1.25 MHZ */
+/* don't need these two for now. --- csy */
+/* time_t secs; /* seconds since boot */
+/* time_t epochsecs; /* seconds since epoch */
+ } time_latch;
+/* a couple in-line assembly codes for efficiency. */
+asm int intr_disable()
+{
+ pushfl
+ cli
+}
+
+asm int intr_restore()
+{
+ popfl
+}
+
+#endif EXL
diff --git a/i386/i386/pmap.h b/i386/i386/pmap.h
new file mode 100644
index 00000000..28b8cead
--- /dev/null
+++ b/i386/i386/pmap.h
@@ -0,0 +1,30 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Now using shared pmap module for i386 and i860.
+ */
+
+#include <intel/pmap.h>
diff --git a/i386/i386/proc_reg.h b/i386/i386/proc_reg.h
new file mode 100644
index 00000000..1aa646b8
--- /dev/null
+++ b/i386/i386/proc_reg.h
@@ -0,0 +1,150 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Processor registers for i386 and i486.
+ */
+#ifndef _I386_PROC_REG_H_
+#define _I386_PROC_REG_H_
+
+/*
+ * CR0
+ */
+#define CR0_PG 0x80000000 /* enable paging */
+#define CR0_CD 0x40000000 /* i486: cache disable */
+#define CR0_NW 0x20000000 /* i486: no write-through */
+#define CR0_AM 0x00040000 /* i486: alignment check mask */
+#define CR0_WP 0x00010000 /* i486: write-protect kernel access */
+#define CR0_NE 0x00000020 /* i486: handle numeric exceptions */
+#define CR0_ET 0x00000010 /* extension type is 80387 */
+ /* (not official) */
+#define CR0_TS 0x00000008 /* task switch */
+#define CR0_EM 0x00000004 /* emulate coprocessor */
+#define CR0_MP 0x00000002 /* monitor coprocessor */
+#define CR0_PE 0x00000001 /* enable protected mode */
+
+#ifndef ASSEMBLER
+#ifdef __GNUC__
+
+static inline unsigned
+get_eflags()
+{
+ unsigned eflags;
+ asm volatile("pushfd; popl %0" : "=r" (eflags));
+ return eflags;
+}
+
+static inline void
+set_eflags(unsigned eflags)
+{
+ asm volatile("pushl %0; popfd" : : "r" (eflags));
+}
+
+#define get_esp() \
+ ({ \
+ register unsigned int _temp__; \
+ asm("mov %%esp, %0" : "=r" (_temp__)); \
+ _temp__; \
+ })
+
+#define get_eflags() \
+ ({ \
+ register unsigned int _temp__; \
+ asm("pushf; popl %0" : "=r" (_temp__)); \
+ _temp__; \
+ })
+
+#define get_cr0() \
+ ({ \
+ register unsigned int _temp__; \
+ asm("mov %%cr0, %0" : "=r" (_temp__)); \
+ _temp__; \
+ })
+
+#define set_cr0(value) \
+ ({ \
+ register unsigned int _temp__ = (value); \
+ asm volatile("mov %0, %%cr0" : : "r" (_temp__)); \
+ })
+
+#define get_cr2() \
+ ({ \
+ register unsigned int _temp__; \
+ asm("mov %%cr2, %0" : "=r" (_temp__)); \
+ _temp__; \
+ })
+
+#define get_cr3() \
+ ({ \
+ register unsigned int _temp__; \
+ asm("mov %%cr3, %0" : "=r" (_temp__)); \
+ _temp__; \
+ })
+
+#define set_cr3(value) \
+ ({ \
+ register unsigned int _temp__ = (value); \
+ asm volatile("mov %0, %%cr3" : : "r" (_temp__)); \
+ })
+
+#define set_ts() \
+ set_cr0(get_cr0() | CR0_TS)
+
+#define clear_ts() \
+ asm volatile("clts")
+
+#define get_tr() \
+ ({ \
+ unsigned short _seg__; \
+ asm volatile("str %0" : "=rm" (_seg__) ); \
+ _seg__; \
+ })
+
+#define set_tr(seg) \
+ asm volatile("ltr %0" : : "rm" ((unsigned short)(seg)) )
+
+#define get_ldt() \
+ ({ \
+ unsigned short _seg__; \
+ asm volatile("sldt %0" : "=rm" (_seg__) ); \
+ _seg__; \
+ })
+
+#define set_ldt(seg) \
+ asm volatile("lldt %0" : : "rm" ((unsigned short)(seg)) )
+
+/* This doesn't set a processor register,
+ but it's often used immediately after setting one,
+ to flush the instruction queue. */
+#define flush_instr_queue() \
+ asm("
+ jmp 0f
+ 0:
+ ")
+
+#endif /* __GNUC__ */
+#endif /* ASSEMBLER */
+
+#endif /* _I386_PROC_REG_H_ */
diff --git a/i386/i386/sched_param.h b/i386/i386/sched_param.h
new file mode 100644
index 00000000..cb372e51
--- /dev/null
+++ b/i386/i386/sched_param.h
@@ -0,0 +1,40 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Scheduler parameters.
+ */
+
+#ifndef _I386_SCHED_PARAM_H_
+#define _I386_SCHED_PARAM_H_
+
+/*
+ * Sequent requires a right shift of 18 bits to convert
+ * microseconds to priorities.
+ */
+
+#define PRI_SHIFT 18
+
+#endif _I386_SCHED_PARAM_H_
diff --git a/i386/i386/seg.c b/i386/i386/seg.c
new file mode 100644
index 00000000..d57c255e
--- /dev/null
+++ b/i386/i386/seg.c
@@ -0,0 +1,5 @@
+
+#define MACH_INLINE
+#include "seg.h"
+#include "tss.h"
+
diff --git a/i386/i386/seg.h b/i386/i386/seg.h
new file mode 100644
index 00000000..b86e967c
--- /dev/null
+++ b/i386/i386/seg.h
@@ -0,0 +1,184 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * Copyright (c) 1991 IBM Corporation
+ * 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,
+ * and that the name IBM not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written
+ * prior permission.
+ *
+ * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_SEG_H_
+#define _I386_SEG_H_
+
+#include <mach/inline.h>
+#include <platforms.h>
+
+/*
+ * i386 segmentation.
+ */
+
+#ifndef ASSEMBLER
+
+/*
+ * Real segment descriptor.
+ */
+struct real_descriptor {
+ unsigned int limit_low:16, /* limit 0..15 */
+ base_low:16, /* base 0..15 */
+ base_med:8, /* base 16..23 */
+ access:8, /* access byte */
+ limit_high:4, /* limit 16..19 */
+ granularity:4, /* granularity */
+ base_high:8; /* base 24..31 */
+};
+
+struct real_gate {
+ unsigned int offset_low:16, /* offset 0..15 */
+ selector:16,
+ word_count:8,
+ access:8,
+ offset_high:16; /* offset 16..31 */
+};
+
+#endif !ASSEMBLER
+
+#define SZ_32 0x4 /* 32-bit segment */
+#define SZ_16 0x0 /* 16-bit segment */
+#define SZ_G 0x8 /* 4K limit field */
+
+#define ACC_A 0x01 /* accessed */
+#define ACC_TYPE 0x1e /* type field: */
+
+#define ACC_TYPE_SYSTEM 0x00 /* system descriptors: */
+
+#define ACC_LDT 0x02 /* LDT */
+#define ACC_CALL_GATE_16 0x04 /* 16-bit call gate */
+#define ACC_TASK_GATE 0x05 /* task gate */
+#define ACC_TSS 0x09 /* task segment */
+#define ACC_CALL_GATE 0x0c /* call gate */
+#define ACC_INTR_GATE 0x0e /* interrupt gate */
+#define ACC_TRAP_GATE 0x0f /* trap gate */
+
+#define ACC_TSS_BUSY 0x02 /* task busy */
+
+#define ACC_TYPE_USER 0x10 /* user descriptors */
+
+#define ACC_DATA 0x10 /* data */
+#define ACC_DATA_W 0x12 /* data, writable */
+#define ACC_DATA_E 0x14 /* data, expand-down */
+#define ACC_DATA_EW 0x16 /* data, expand-down,
+ writable */
+#define ACC_CODE 0x18 /* code */
+#define ACC_CODE_R 0x1a /* code, readable */
+#define ACC_CODE_C 0x1c /* code, conforming */
+#define ACC_CODE_CR 0x1e /* code, conforming,
+ readable */
+#define ACC_PL 0x60 /* access rights: */
+#define ACC_PL_K 0x00 /* kernel access only */
+#define ACC_PL_U 0x60 /* user access */
+#define ACC_P 0x80 /* segment present */
+
+/*
+ * Components of a selector
+ */
+#define SEL_LDT 0x04 /* local selector */
+#define SEL_PL 0x03 /* privilege level: */
+#define SEL_PL_K 0x00 /* kernel selector */
+#define SEL_PL_U 0x03 /* user selector */
+
+/*
+ * Convert selector to descriptor table index.
+ */
+#define sel_idx(sel) ((sel)>>3)
+
+
+#ifndef ASSEMBLER
+
+#include <mach/inline.h>
+
+
+/* Format of a "pseudo-descriptor", used for loading the IDT and GDT. */
+struct pseudo_descriptor
+{
+ short pad;
+ unsigned short limit;
+ unsigned long linear_base;
+};
+
+
+/* Load the processor's IDT, GDT, or LDT pointers. */
+MACH_INLINE void lgdt(struct pseudo_descriptor *pdesc)
+{
+ __asm volatile("lgdt %0" : : "m" (pdesc->limit));
+}
+MACH_INLINE void lidt(struct pseudo_descriptor *pdesc)
+{
+ __asm volatile("lidt %0" : : "m" (pdesc->limit));
+}
+MACH_INLINE void lldt(unsigned short ldt_selector)
+{
+ __asm volatile("lldt %w0" : : "r" (ldt_selector));
+}
+
+#ifdef CODE16
+#define i16_lgdt lgdt
+#define i16_lidt lidt
+#define i16_lldt lldt
+#endif
+
+
+/* Fill a segment descriptor. */
+MACH_INLINE void
+fill_descriptor(struct real_descriptor *desc, unsigned base, unsigned limit,
+ unsigned char access, unsigned char sizebits)
+{
+ if (limit > 0xfffff)
+ {
+ limit >>= 12;
+ sizebits |= SZ_G;
+ }
+ desc->limit_low = limit & 0xffff;
+ desc->base_low = base & 0xffff;
+ desc->base_med = (base >> 16) & 0xff;
+ desc->access = access | ACC_P;
+ desc->limit_high = limit >> 16;
+ desc->granularity = sizebits;
+ desc->base_high = base >> 24;
+}
+
+/* Fill a gate with particular values. */
+MACH_INLINE void
+fill_gate(struct real_gate *gate, unsigned offset, unsigned short selector,
+ unsigned char access, unsigned char word_count)
+{
+ gate->offset_low = offset & 0xffff;
+ gate->selector = selector;
+ gate->word_count = word_count;
+ gate->access = access | ACC_P;
+ gate->offset_high = (offset >> 16) & 0xffff;
+}
+
+#endif !ASSEMBLER
+
+#endif /* _I386_SEG_H_ */
diff --git a/i386/i386/setjmp.h b/i386/i386/setjmp.h
new file mode 100644
index 00000000..21c856dc
--- /dev/null
+++ b/i386/i386/setjmp.h
@@ -0,0 +1,36 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Setjmp/longjmp buffer for i386.
+ */
+#ifndef _I386_SETJMP_H_
+#define _I386_SETJMP_H_
+
+typedef struct jmp_buf {
+ int jmp_buf[6]; /* ebx, esi, edi, ebp, esp, eip */
+} jmp_buf_t;
+
+#endif /* _I386_SETJMP_H_ */
diff --git a/i386/i386/spl.S b/i386/i386/spl.S
new file mode 100644
index 00000000..f77b5563
--- /dev/null
+++ b/i386/i386/spl.S
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 1995 Shantanu Goel
+ * 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.
+ *
+ * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ */
+
+/*
+ * spl routines for the i386at.
+ */
+
+#include <mach/machine/asm.h>
+#include <i386/ipl.h>
+#include <i386/pic.h>
+
+/*
+ * Set IPL to the specified value.
+ *
+ * NOTE: Normally we would not have to enable interrupts
+ * here. Linux drivers, however, use cli()/sti(), so we must
+ * guard against the case where a Mach routine which
+ * has done an spl() calls a Linux routine that returns
+ * with interrupts disabled. A subsequent splx() can,
+ * potentially, return with interrupts disabled.
+ */
+#define SETIPL(level) \
+ movl $(level),%edx; \
+ cmpl EXT(curr_ipl),%edx; \
+ jne spl; \
+ sti; \
+ movl %edx,%eax; \
+ ret
+
+/*
+ * Program PICs with mask in %eax.
+ */
+#define SETMASK() \
+ cmpl EXT(curr_pic_mask),%eax; \
+ je 9f; \
+ outb %al,$(PIC_MASTER_OCW); \
+ movl %eax,EXT(curr_pic_mask); \
+ movb %ah,%al; \
+ outb %al,$(PIC_SLAVE_OCW); \
+9:
+
+ENTRY(spl0)
+ movl EXT(curr_ipl),%eax /* save current ipl */
+ pushl %eax
+ cli /* disable interrupts */
+#ifdef LINUX_DEV
+ movl EXT(bh_active),%eax
+ /* get pending mask */
+ andl EXT(bh_mask),%eax /* any pending unmasked interrupts? */
+ jz 1f /* no, skip */
+ call EXT(spl1) /* block further interrupts */
+ incl EXT(intr_count) /* set interrupt flag */
+ call EXT(linux_soft_intr) /* go handle interrupt */
+ decl EXT(intr_count) /* decrement interrupt flag */
+ cli /* disable interrupts */
+1:
+#endif
+ cmpl $0,softclkpending /* softclock pending? */
+ je 1f /* no, skip */
+ movl $0,softclkpending /* clear flag */
+ call EXT(spl1) /* block further interrupts */
+#ifdef LINUX_DEV
+ incl EXT(intr_count) /* set interrupt flag */
+#endif
+ call EXT(softclock) /* go handle interrupt */
+#ifdef LINUX_DEV
+ decl EXT(intr_count) /* decrement interrupt flag */
+#endif
+ cli /* disable interrupts */
+1:
+ cmpl $(SPL0),EXT(curr_ipl) /* are we at spl0? */
+ je 1f /* yes, all done */
+ movl $(SPL0),EXT(curr_ipl) /* set ipl */
+ movl EXT(pic_mask)+SPL0*4,%eax
+ /* get PIC mask */
+ SETMASK() /* program PICs with new mask */
+1:
+ sti /* enable interrupts */
+ popl %eax /* return previous mask */
+ ret
+
+Entry(splsoftclock)
+ENTRY(spl1)
+ SETIPL(SPL1)
+
+ENTRY(spl2)
+ SETIPL(SPL2)
+
+ENTRY(spl3)
+ SETIPL(SPL3)
+
+Entry(splnet)
+Entry(splhdw)
+ENTRY(spl4)
+ SETIPL(SPL4)
+
+Entry(splbio)
+Entry(spldcm)
+ENTRY(spl5)
+ SETIPL(SPL5)
+
+Entry(spltty)
+Entry(splimp)
+Entry(splvm)
+ENTRY(spl6)
+ SETIPL(SPL6)
+
+Entry(splclock)
+Entry(splsched)
+Entry(splhigh)
+Entry(splhi)
+ENTRY(spl7)
+ SETIPL(SPL7)
+
+ENTRY(splx)
+ movl 4(%esp),%edx /* get ipl */
+ testl %edx,%edx /* spl0? */
+ jz EXT(spl0) /* yes, handle specially */
+ cmpl EXT(curr_ipl),%edx /* same ipl as current? */
+ jne spl /* no */
+ sti /* ensure interrupts are enabled */
+ movl %edx,%eax /* return previous ipl */
+ ret
+
+/*
+ * Like splx() but returns with interrupts disabled and does
+ * not return the previous ipl. This should only be called
+ * when returning from an interrupt.
+ */
+ .align TEXT_ALIGN
+ .globl splx_cli
+splx_cli:
+ movl 4(%esp),%edx /* get ipl */
+ cli /* disable interrupts */
+ testl %edx,%edx /* spl0? */
+ jnz 2f /* no, skip */
+#ifdef LINUX_DEV
+ movl EXT(bh_active),%eax
+ /* get pending mask */
+ andl EXT(bh_mask),%eax /* any pending unmasked interrupts? */
+ jz 1f /* no, skip */
+ call EXT(spl1) /* block further interrupts */
+ incl EXT(intr_count) /* set interrupt flag */
+ call EXT(linux_soft_intr) /* go handle interrupt */
+ decl EXT(intr_count) /* decrement interrupt flag */
+ cli /* disable interrupts */
+1:
+#endif
+ cmpl $0,softclkpending /* softclock pending? */
+ je 1f /* no, skip */
+ movl $0,softclkpending /* clear flag */
+ call EXT(spl1) /* block further interrupts */
+#ifdef LINUX_DEV
+ incl EXT(intr_count) /* set interrupt flag */
+#endif
+ call EXT(softclock) /* go handle interrupt */
+#ifdef LINUX_DEV
+ decl EXT(intr_count) /* decrement interrupt flag */
+#endif
+ cli /* disable interrupts */
+1:
+ xorl %edx,%edx /* edx = ipl 0 */
+2:
+ cmpl EXT(curr_ipl),%edx /* same ipl as current? */
+ je 1f /* yes, all done */
+ movl %edx,EXT(curr_ipl) /* set ipl */
+ movl EXT(pic_mask)(,%edx,4),%eax
+ /* get PIC mask */
+ SETMASK() /* program PICs with new mask */
+1:
+ ret
+
+/*
+ * NOTE: This routine must *not* use %ecx, otherwise
+ * the interrupt code will break.
+ */
+ .align TEXT_ALIGN
+ .globl spl
+spl:
+ movl EXT(pic_mask)(,%edx,4),%eax
+ /* get PIC mask */
+ cli /* disable interrupts */
+ xchgl EXT(curr_ipl),%edx /* set ipl */
+ SETMASK() /* program PICs with new mask */
+ sti /* enable interrupts */
+ movl %edx,%eax /* return previous ipl */
+ ret
+
+ENTRY(sploff)
+ pushfl
+ popl %eax
+ cli
+ ret
+
+ENTRY(splon)
+ pushl 4(%esp)
+ popfl
+ ret
+
+ .data
+ .align DATA_ALIGN
+softclkpending:
+ .long 0
+ .text
+
+ENTRY(setsoftclock)
+ incl softclkpending
+ ret
diff --git a/i386/i386/spl.h b/i386/i386/spl.h
new file mode 100644
index 00000000..219ee9f2
--- /dev/null
+++ b/i386/i386/spl.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990
+ * Open Software Foundation, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of ("OSF") or Open Software
+ * Foundation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE
+ */
+/*
+ * OSF Research Institute MK6.1 (unencumbered) 1/31/1995
+ */
+
+#ifndef _MACHINE_SPL_H_
+#define _MACHINE_SPL_H_
+
+/*
+ * This file defines the interrupt priority levels used by
+ * machine-dependent code.
+ */
+
+typedef int spl_t;
+
+extern spl_t (splhi)(void);
+
+extern spl_t (spl1)(void);
+
+extern spl_t (spl2)(void);
+
+extern spl_t (spl3)(void);
+
+extern spl_t (spl4)(void);
+extern spl_t (splhdw)(void);
+
+extern spl_t (spl5)(void);
+extern spl_t (spldcm)(void);
+
+extern spl_t (spl6)(void);
+
+#endif /* _MACHINE_SPL_H_ */
diff --git a/i386/i386/thread.h b/i386/i386/thread.h
new file mode 100644
index 00000000..922427eb
--- /dev/null
+++ b/i386/i386/thread.h
@@ -0,0 +1,195 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * File: machine/thread.h
+ *
+ * This file contains the structure definitions for the thread
+ * state as applied to I386 processors.
+ */
+
+#ifndef _I386_THREAD_H_
+#define _I386_THREAD_H_
+
+#include <mach/boolean.h>
+#include <mach/machine/vm_types.h>
+#include <mach/machine/fp_reg.h>
+
+#include <kern/lock.h>
+
+#include <i386/iopb.h>
+#include <i386/tss.h>
+
+/*
+ * i386_saved_state:
+ *
+ * This structure corresponds to the state of user registers
+ * as saved upon kernel entry. It lives in the pcb.
+ * It is also pushed onto the stack for exceptions in the kernel.
+ */
+
+struct i386_saved_state {
+ unsigned int gs;
+ unsigned int fs;
+ unsigned int es;
+ unsigned int ds;
+ unsigned int edi;
+ unsigned int esi;
+ unsigned int ebp;
+ unsigned int cr2; /* kernel esp stored by pusha -
+ we save cr2 here later */
+ unsigned int ebx;
+ unsigned int edx;
+ unsigned int ecx;
+ unsigned int eax;
+ unsigned int trapno;
+ unsigned int err;
+ unsigned int eip;
+ unsigned int cs;
+ unsigned int efl;
+ unsigned int uesp;
+ unsigned int ss;
+ struct v86_segs {
+ unsigned int v86_es; /* virtual 8086 segment registers */
+ unsigned int v86_ds;
+ unsigned int v86_fs;
+ unsigned int v86_gs;
+ } v86_segs;
+};
+
+/*
+ * i386_exception_link:
+ *
+ * This structure lives at the high end of the kernel stack.
+ * It points to the current thread`s user registers.
+ */
+struct i386_exception_link {
+ struct i386_saved_state *saved_state;
+};
+
+/*
+ * i386_kernel_state:
+ *
+ * This structure corresponds to the state of kernel registers
+ * as saved in a context-switch. It lives at the base of the stack.
+ */
+
+struct i386_kernel_state {
+ int k_ebx; /* kernel context */
+ int k_esp;
+ int k_ebp;
+ int k_edi;
+ int k_esi;
+ int k_eip;
+};
+
+/*
+ * Save area for user floating-point state.
+ * Allocated only when necessary.
+ */
+
+struct i386_fpsave_state {
+ boolean_t fp_valid;
+ struct i386_fp_save fp_save_state;
+ struct i386_fp_regs fp_regs;
+};
+
+/*
+ * v86_assist_state:
+ *
+ * This structure provides data to simulate 8086 mode
+ * interrupts. It lives in the pcb.
+ */
+
+struct v86_assist_state {
+ vm_offset_t int_table;
+ unsigned short int_count;
+ unsigned short flags; /* 8086 flag bits */
+};
+#define V86_IF_PENDING 0x8000 /* unused bit */
+
+/*
+ * i386_interrupt_state:
+ *
+ * This structure describes the set of registers that must
+ * be pushed on the current ring-0 stack by an interrupt before
+ * we can switch to the interrupt stack.
+ */
+
+struct i386_interrupt_state {
+ int es;
+ int ds;
+ int edx;
+ int ecx;
+ int eax;
+ int eip;
+ int cs;
+ int efl;
+};
+
+/*
+ * i386_machine_state:
+ *
+ * This structure corresponds to special machine state.
+ * It lives in the pcb. It is not saved by default.
+ */
+
+struct i386_machine_state {
+ iopb_tss_t io_tss;
+ struct user_ldt * ldt;
+ struct i386_fpsave_state *ifps;
+ struct v86_assist_state v86s;
+};
+
+typedef struct pcb {
+ struct i386_interrupt_state iis[2]; /* interrupt and NMI */
+ struct i386_saved_state iss;
+ struct i386_machine_state ims;
+ decl_simple_lock_data(, lock)
+} *pcb_t;
+
+/*
+ * On the kernel stack is:
+ * stack: ...
+ * struct i386_exception_link
+ * struct i386_kernel_state
+ * stack+KERNEL_STACK_SIZE
+ */
+
+#define STACK_IKS(stack) \
+ ((struct i386_kernel_state *)((stack) + KERNEL_STACK_SIZE) - 1)
+#define STACK_IEL(stack) \
+ ((struct i386_exception_link *)STACK_IKS(stack) - 1)
+
+#define USER_REGS(thread) (&(thread)->pcb->iss)
+
+
+#define syscall_emulation_sync(task) /* do nothing */
+
+
+/* #include_next "thread.h" */
+
+
+#endif _I386_THREAD_H_
diff --git a/i386/i386/time_stamp.h b/i386/i386/time_stamp.h
new file mode 100644
index 00000000..43bb956b
--- /dev/null
+++ b/i386/i386/time_stamp.h
@@ -0,0 +1,30 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * The i386 timestamp implementation uses the default, so we don't
+ * need to do anything here.
+ */
+
diff --git a/i386/i386/timer.h b/i386/i386/timer.h
new file mode 100644
index 00000000..b74965df
--- /dev/null
+++ b/i386/i386/timer.h
@@ -0,0 +1,71 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_TIMER_H_
+#define _I386_TIMER_H_
+
+/*
+ * Machine dependent timer definitions.
+ */
+
+#include <platforms.h>
+
+#ifdef SYMMETRY
+
+/*
+ * TIMER_MAX is not used on the Sequent because a 32-bit rollover
+ * timer does not need to be adjusted for maximum value.
+ */
+
+/*
+ * TIMER_RATE is the rate of the timer in ticks per second.
+ * It is used to calculate percent cpu usage.
+ */
+
+#define TIMER_RATE 1000000
+
+/*
+ * TIMER_HIGH_UNIT is the unit for high_bits in terms of low_bits.
+ * Setting it to TIMER_RATE makes the high unit seconds.
+ */
+
+#define TIMER_HIGH_UNIT TIMER_RATE
+
+/*
+ * TIMER_ADJUST is used to adjust the value of a timer after
+ * it has been copied into a time_value_t. No adjustment is needed
+ * on Sequent because high_bits is in seconds.
+ */
+
+/*
+ * MACHINE_TIMER_ROUTINES should defined if the timer routines are
+ * implemented in machine-dependent code (e.g. assembly language).
+ */
+#define MACHINE_TIMER_ROUTINES
+
+#endif
+
+#endif /* _I386_TIMER_H_ */
diff --git a/i386/i386/trap.c b/i386/i386/trap.c
new file mode 100644
index 00000000..6096a39f
--- /dev/null
+++ b/i386/i386/trap.c
@@ -0,0 +1,1139 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Hardware trap/fault handler.
+ */
+
+#include <cpus.h>
+#include <fpe.h>
+#include <mach_kdb.h>
+#include <mach_ttd.h>
+#include <mach_pcsample.h>
+
+#include <sys/types.h>
+#include <mach/machine/eflags.h>
+#include <i386/trap.h>
+#include <machine/machspl.h> /* for spl_t */
+
+#include <mach/exception.h>
+#include <mach/kern_return.h>
+#include "vm_param.h"
+#include <mach/machine/thread_status.h>
+
+#include <vm/vm_kern.h>
+#include <vm/vm_map.h>
+
+#include <kern/ast.h>
+#include <kern/thread.h>
+#include <kern/task.h>
+#include <kern/sched.h>
+#include <kern/sched_prim.h>
+
+#include <i386/io_emulate.h>
+
+#include "debug.h"
+
+extern void exception();
+extern void thread_exception_return();
+
+extern void i386_exception();
+
+#if MACH_KDB
+boolean_t debug_all_traps_with_kdb = FALSE;
+extern struct db_watchpoint *db_watchpoint_list;
+extern boolean_t db_watchpoints_inserted;
+
+void
+thread_kdb_return()
+{
+ register thread_t thread = current_thread();
+ register struct i386_saved_state *regs = USER_REGS(thread);
+
+ if (kdb_trap(regs->trapno, regs->err, regs)) {
+ thread_exception_return();
+ /*NOTREACHED*/
+ }
+}
+#endif MACH_KDB
+
+#if MACH_TTD
+extern boolean_t kttd_enabled;
+boolean_t debug_all_traps_with_kttd = TRUE;
+#endif MACH_TTD
+
+void
+user_page_fault_continue(kr)
+ kern_return_t kr;
+{
+ register thread_t thread = current_thread();
+ register struct i386_saved_state *regs = USER_REGS(thread);
+
+ if (kr == KERN_SUCCESS) {
+#if MACH_KDB
+ if (db_watchpoint_list &&
+ db_watchpoints_inserted &&
+ (regs->err & T_PF_WRITE) &&
+ db_find_watchpoint(thread->task->map,
+ (vm_offset_t)regs->cr2,
+ regs))
+ kdb_trap(T_WATCHPOINT, 0, regs);
+#endif MACH_KDB
+ thread_exception_return();
+ /*NOTREACHED*/
+ }
+
+#if MACH_KDB
+ if (debug_all_traps_with_kdb &&
+ kdb_trap(regs->trapno, regs->err, regs)) {
+ thread_exception_return();
+ /*NOTREACHED*/
+ }
+#endif MACH_KDB
+
+ i386_exception(EXC_BAD_ACCESS, kr, regs->cr2);
+ /*NOTREACHED*/
+}
+
+/*
+ * Fault recovery in copyin/copyout routines.
+ */
+struct recovery {
+ int fault_addr;
+ int recover_addr;
+};
+
+extern struct recovery recover_table[];
+extern struct recovery recover_table_end[];
+
+/*
+ * Recovery from Successful fault in copyout does not
+ * return directly - it retries the pte check, since
+ * the 386 ignores write protection in kernel mode.
+ */
+extern struct recovery retry_table[];
+extern struct recovery retry_table_end[];
+
+
+static char *trap_type[] = {
+ "Divide error",
+ "Debug trap",
+ "NMI",
+ "Breakpoint",
+ "Overflow",
+ "Bounds check",
+ "Invalid opcode",
+ "No coprocessor",
+ "Double fault",
+ "Coprocessor overrun",
+ "Invalid TSS",
+ "Segment not present",
+ "Stack bounds",
+ "General protection",
+ "Page fault",
+ "(reserved)",
+ "Coprocessor error"
+};
+#define TRAP_TYPES (sizeof(trap_type)/sizeof(trap_type[0]))
+
+char *trap_name(unsigned int trapnum)
+{
+ return trapnum < TRAP_TYPES ? trap_type[trapnum] : "(unknown)";
+}
+
+
+boolean_t brb = TRUE;
+
+/*
+ * Trap from kernel mode. Only page-fault errors are recoverable,
+ * and then only in special circumstances. All other errors are
+ * fatal.
+ */
+void kernel_trap(regs)
+ register struct i386_saved_state *regs;
+{
+ int exc;
+ int code;
+ int subcode;
+ register int type;
+ vm_map_t map;
+ kern_return_t result;
+ register thread_t thread;
+ extern char start[], etext[];
+
+ type = regs->trapno;
+ code = regs->err;
+ thread = current_thread();
+
+#if 0
+((short*)0xb8700)[0] = 0x0f00+'K';
+((short*)0xb8700)[1] = 0x0f30+(type / 10);
+((short*)0xb8700)[2] = 0x0f30+(type % 10);
+#endif
+#if 0
+printf("kernel trap %d error %d\n", type, code);
+dump_ss(regs);
+#endif
+
+ switch (type) {
+ case T_NO_FPU:
+ fpnoextflt();
+ return;
+
+ case T_FPU_FAULT:
+ fpextovrflt();
+ return;
+
+ case T_FLOATING_POINT_ERROR:
+ fpexterrflt();
+ return;
+
+ case T_PAGE_FAULT:
+
+ /* Get faulting linear address */
+ subcode = regs->cr2;
+#if 0
+ printf("kernel page fault at linear address %08x\n", subcode);
+#endif
+
+ /* If it's in the kernel linear address region,
+ convert it to a kernel virtual address
+ and use the kernel map to process the fault. */
+ if (subcode >= LINEAR_MIN_KERNEL_ADDRESS) {
+#if 0
+ printf("%08x in kernel linear address range\n", subcode);
+#endif
+ map = kernel_map;
+ subcode = lintokv(subcode);
+#if 0
+ printf("now %08x\n", subcode);
+#endif
+ if (trunc_page(subcode) == 0
+ || (subcode >= (int)start
+ && subcode < (int)etext)) {
+ printf("Kernel page fault at address 0x%x, "
+ "eip = 0x%x\n",
+ subcode, regs->eip);
+ goto badtrap;
+ }
+ } else {
+ assert(thread);
+ map = thread->task->map;
+ if (map == kernel_map) {
+ printf("kernel page fault at %08x:\n");
+ dump_ss(regs);
+ panic("kernel thread accessed user space!\n");
+ }
+ }
+
+ /*
+ * Since the 386 ignores write protection in
+ * kernel mode, always try for write permission
+ * first. If that fails and the fault was a
+ * read fault, retry with read permission.
+ */
+ result = vm_fault(map,
+ trunc_page((vm_offset_t)subcode),
+ VM_PROT_READ|VM_PROT_WRITE,
+ FALSE,
+ FALSE,
+ (void (*)()) 0);
+#if MACH_KDB
+ if (result == KERN_SUCCESS) {
+ /* Look for watchpoints */
+ if (db_watchpoint_list &&
+ db_watchpoints_inserted &&
+ (code & T_PF_WRITE) &&
+ db_find_watchpoint(map,
+ (vm_offset_t)subcode, regs))
+ kdb_trap(T_WATCHPOINT, 0, regs);
+ }
+ else
+#endif MACH_KDB
+ if ((code & T_PF_WRITE) == 0 &&
+ result == KERN_PROTECTION_FAILURE)
+ {
+ /*
+ * Must expand vm_fault by hand,
+ * so that we can ask for read-only access
+ * but enter a (kernel)writable mapping.
+ */
+ result = intel_read_fault(map,
+ trunc_page((vm_offset_t)subcode));
+ }
+
+ if (result == KERN_SUCCESS) {
+ /*
+ * Certain faults require that we back up
+ * the EIP.
+ */
+ register struct recovery *rp;
+
+ for (rp = retry_table; rp < retry_table_end; rp++) {
+ if (regs->eip == rp->fault_addr) {
+ regs->eip = rp->recover_addr;
+ break;
+ }
+ }
+ return;
+ }
+
+ /*
+ * If there is a failure recovery address
+ * for this fault, go there.
+ */
+ {
+ register struct recovery *rp;
+
+ for (rp = recover_table;
+ rp < recover_table_end;
+ rp++) {
+ if (regs->eip == rp->fault_addr) {
+ regs->eip = rp->recover_addr;
+ return;
+ }
+ }
+ }
+
+ /*
+ * Check thread recovery address also -
+ * v86 assist uses it.
+ */
+ if (thread->recover) {
+ regs->eip = thread->recover;
+ thread->recover = 0;
+ return;
+ }
+
+ /*
+ * Unanticipated page-fault errors in kernel
+ * should not happen.
+ */
+ /* fall through */
+
+ default:
+ badtrap:
+ printf("Kernel ");
+ if (type < TRAP_TYPES)
+ printf("%s trap", trap_type[type]);
+ else
+ printf("trap %d", type);
+ printf(", eip 0x%x\n", regs->eip);
+#if MACH_TTD
+ if (kttd_enabled && kttd_trap(type, code, regs))
+ return;
+#endif /* MACH_TTD */
+#if MACH_KDB
+ if (kdb_trap(type, code, regs))
+ return;
+#endif MACH_KDB
+ splhigh();
+ printf("kernel trap, type %d, code = %x\n",
+ type, code);
+ dump_ss(regs);
+ panic("trap");
+ return;
+ }
+}
+
+
+/*
+ * Trap from user mode.
+ * Return TRUE if from emulated system call.
+ */
+int user_trap(regs)
+ register struct i386_saved_state *regs;
+{
+ int exc;
+ int code;
+ int subcode;
+ register int type;
+ vm_map_t map;
+ kern_return_t result;
+ register thread_t thread = current_thread();
+ extern vm_offset_t phys_last_addr;
+
+ if ((vm_offset_t)thread < phys_last_addr) {
+ printf("user_trap: bad thread pointer 0x%x\n", thread);
+ printf("trap type %d, code 0x%x, va 0x%x, eip 0x%x\n",
+ regs->trapno, regs->err, regs->cr2, regs->eip);
+ asm volatile ("1: hlt; jmp 1b");
+ }
+#if 0
+printf("user trap %d error %d sub %08x\n", type, code, subcode);
+#endif
+
+ if (regs->efl & EFL_VM) {
+ /*
+ * If hardware assist can handle exception,
+ * continue execution.
+ */
+ if (v86_assist(thread, regs))
+ return 0;
+ }
+
+ type = regs->trapno;
+ code = 0;
+ subcode = 0;
+
+#if 0
+ ((short*)0xb8700)[3] = 0x0f00+'U';
+ ((short*)0xb8700)[4] = 0x0f30+(type / 10);
+ ((short*)0xb8700)[5] = 0x0f30+(type % 10);
+#endif
+#if 0
+ printf("user trap %d error %d\n", type, code);
+ dump_ss(regs);
+#endif
+
+ switch (type) {
+
+ case T_DIVIDE_ERROR:
+ exc = EXC_ARITHMETIC;
+ code = EXC_I386_DIV;
+ break;
+
+ case T_DEBUG:
+#if MACH_TTD
+ if (kttd_enabled && kttd_in_single_step()) {
+ if (kttd_trap(type, regs->err, regs))
+ return 0;
+ }
+#endif /* MACH_TTD */
+#if MACH_KDB
+ if (db_in_single_step()) {
+ if (kdb_trap(type, regs->err, regs))
+ return 0;
+ }
+#endif
+ exc = EXC_BREAKPOINT;
+ code = EXC_I386_SGL;
+ break;
+
+ case T_INT3:
+#if MACH_TTD
+ if (kttd_enabled && kttd_trap(type, regs->err, regs))
+ return 0;
+ break;
+#endif /* MACH_TTD */
+#if MACH_KDB
+ {
+ boolean_t db_find_breakpoint_here();
+
+ if (db_find_breakpoint_here(
+ (current_thread())? current_thread()->task: TASK_NULL,
+ regs->eip - 1)) {
+ if (kdb_trap(type, regs->err, regs))
+ return 0;
+ }
+ }
+#endif
+ exc = EXC_BREAKPOINT;
+ code = EXC_I386_BPT;
+ break;
+
+ case T_OVERFLOW:
+ exc = EXC_ARITHMETIC;
+ code = EXC_I386_INTO;
+ break;
+
+ case T_OUT_OF_BOUNDS:
+ exc = EXC_SOFTWARE;
+ code = EXC_I386_BOUND;
+ break;
+
+ case T_INVALID_OPCODE:
+ exc = EXC_BAD_INSTRUCTION;
+ code = EXC_I386_INVOP;
+ break;
+
+ case T_NO_FPU:
+ case 32: /* XXX */
+ fpnoextflt();
+ return 0;
+
+ case T_FPU_FAULT:
+ fpextovrflt();
+ return 0;
+
+ case 10: /* invalid TSS == iret with NT flag set */
+ exc = EXC_BAD_INSTRUCTION;
+ code = EXC_I386_INVTSSFLT;
+ subcode = regs->err & 0xffff;
+ break;
+
+ case T_SEGMENT_NOT_PRESENT:
+#if FPE
+ if (fp_emul_error(regs))
+ return 0;
+#endif /* FPE */
+
+ exc = EXC_BAD_INSTRUCTION;
+ code = EXC_I386_SEGNPFLT;
+ subcode = regs->err & 0xffff;
+ break;
+
+ case T_STACK_FAULT:
+ exc = EXC_BAD_INSTRUCTION;
+ code = EXC_I386_STKFLT;
+ subcode = regs->err & 0xffff;
+ break;
+
+ case T_GENERAL_PROTECTION:
+ if (!(regs->efl & EFL_VM)) {
+ if (check_io_fault(regs))
+ return 0;
+ }
+ /* Check for an emulated int80 system call.
+ NetBSD-current and Linux use trap instead of call gate. */
+ if (thread->task->eml_dispatch) {
+ unsigned char opcode, intno;
+
+ opcode = inst_fetch(regs->eip, regs->cs);
+ intno = inst_fetch(regs->eip+1, regs->cs);
+ if (opcode == 0xcd && intno == 0x80) {
+ regs->eip += 2;
+ return 1;
+ }
+ }
+ exc = EXC_BAD_INSTRUCTION;
+ code = EXC_I386_GPFLT;
+ subcode = regs->err & 0xffff;
+ break;
+
+ case T_PAGE_FAULT:
+#if 0
+ printf("user page fault at linear address %08x\n", subcode);
+#endif
+ assert(subcode < LINEAR_MIN_KERNEL_ADDRESS);
+ subcode = regs->cr2;
+ (void) vm_fault(thread->task->map,
+ trunc_page((vm_offset_t)subcode),
+ (regs->err & T_PF_WRITE)
+ ? VM_PROT_READ|VM_PROT_WRITE
+ : VM_PROT_READ,
+ FALSE,
+ FALSE,
+ user_page_fault_continue);
+ /*NOTREACHED*/
+ break;
+
+ case T_FLOATING_POINT_ERROR:
+ fpexterrflt();
+ return 0;
+
+ default:
+#if MACH_TTD
+ if (kttd_enabled && kttd_trap(type, regs->err, regs))
+ return 0;
+#endif /* MACH_TTD */
+#if MACH_KDB
+ if (kdb_trap(type, regs->err, regs))
+ return 0;
+#endif MACH_KDB
+ splhigh();
+ printf("user trap, type %d, code = %x\n",
+ type, regs->err);
+ dump_ss(regs);
+ panic("trap");
+ return 0;
+ }
+
+#if MACH_TTD
+ if (debug_all_traps_with_kttd && kttd_trap(type, regs->err, regs))
+ return 0;
+#endif /* MACH_TTD */
+#if MACH_KDB
+ if (debug_all_traps_with_kdb &&
+ kdb_trap(type, regs->err, regs))
+ return 0;
+#endif MACH_KDB
+
+ i386_exception(exc, code, subcode);
+ /*NOTREACHED*/
+}
+
+/*
+ * V86 mode assist for interrupt handling.
+ */
+boolean_t v86_assist_on = TRUE;
+boolean_t v86_unsafe_ok = FALSE;
+boolean_t v86_do_sti_cli = TRUE;
+boolean_t v86_do_sti_immediate = FALSE;
+
+#define V86_IRET_PENDING 0x4000
+
+int cli_count = 0;
+int sti_count = 0;
+
+boolean_t
+v86_assist(thread, regs)
+ thread_t thread;
+ register struct i386_saved_state *regs;
+{
+ register struct v86_assist_state *v86 = &thread->pcb->ims.v86s;
+
+/*
+ * Build an 8086 address. Use only when off is known to be 16 bits.
+ */
+#define Addr8086(seg,off) ((((seg) & 0xffff) << 4) + (off))
+
+#define EFL_V86_SAFE ( EFL_OF | EFL_DF | EFL_TF \
+ | EFL_SF | EFL_ZF | EFL_AF \
+ | EFL_PF | EFL_CF )
+ struct iret_32 {
+ int eip;
+ int cs;
+ int eflags;
+ };
+ struct iret_16 {
+ unsigned short ip;
+ unsigned short cs;
+ unsigned short flags;
+ };
+ union iret_struct {
+ struct iret_32 iret_32;
+ struct iret_16 iret_16;
+ };
+
+ struct int_vec {
+ unsigned short ip;
+ unsigned short cs;
+ };
+
+ if (!v86_assist_on)
+ return FALSE;
+
+ /*
+ * If delayed STI pending, enable interrupts.
+ * Turn off tracing if on only to delay STI.
+ */
+ if (v86->flags & V86_IF_PENDING) {
+ v86->flags &= ~V86_IF_PENDING;
+ v86->flags |= EFL_IF;
+ if ((v86->flags & EFL_TF) == 0)
+ regs->efl &= ~EFL_TF;
+ }
+
+ if (regs->trapno == T_DEBUG) {
+
+ if (v86->flags & EFL_TF) {
+ /*
+ * Trace flag was also set - it has priority
+ */
+ return FALSE; /* handle as single-step */
+ }
+ /*
+ * Fall through to check for interrupts.
+ */
+ }
+ else if (regs->trapno == T_GENERAL_PROTECTION) {
+ /*
+ * General protection error - must be an 8086 instruction
+ * to emulate.
+ */
+ register int eip;
+ boolean_t addr_32 = FALSE;
+ boolean_t data_32 = FALSE;
+ int io_port;
+
+ /*
+ * Set up error handler for bad instruction/data
+ * fetches.
+ */
+ asm("movl $(addr_error), %0" : "=m" (thread->recover));
+
+ eip = regs->eip;
+ while (TRUE) {
+ unsigned char opcode;
+
+ if (eip > 0xFFFF) {
+ thread->recover = 0;
+ return FALSE; /* GP fault: IP out of range */
+ }
+
+ opcode = *(unsigned char *)Addr8086(regs->cs,eip);
+ eip++;
+ switch (opcode) {
+ case 0xf0: /* lock */
+ case 0xf2: /* repne */
+ case 0xf3: /* repe */
+ case 0x2e: /* cs */
+ case 0x36: /* ss */
+ case 0x3e: /* ds */
+ case 0x26: /* es */
+ case 0x64: /* fs */
+ case 0x65: /* gs */
+ /* ignore prefix */
+ continue;
+
+ case 0x66: /* data size */
+ data_32 = TRUE;
+ continue;
+
+ case 0x67: /* address size */
+ addr_32 = TRUE;
+ continue;
+
+ case 0xe4: /* inb imm */
+ case 0xe5: /* inw imm */
+ case 0xe6: /* outb imm */
+ case 0xe7: /* outw imm */
+ io_port = *(unsigned char *)Addr8086(regs->cs, eip);
+ eip++;
+ goto do_in_out;
+
+ case 0xec: /* inb dx */
+ case 0xed: /* inw dx */
+ case 0xee: /* outb dx */
+ case 0xef: /* outw dx */
+ case 0x6c: /* insb */
+ case 0x6d: /* insw */
+ case 0x6e: /* outsb */
+ case 0x6f: /* outsw */
+ io_port = regs->edx & 0xffff;
+
+ do_in_out:
+ if (!data_32)
+ opcode |= 0x6600; /* word IO */
+
+ switch (emulate_io(regs, opcode, io_port)) {
+ case EM_IO_DONE:
+ /* instruction executed */
+ break;
+ case EM_IO_RETRY:
+ /* port mapped, retry instruction */
+ thread->recover = 0;
+ return TRUE;
+ case EM_IO_ERROR:
+ /* port not mapped */
+ thread->recover = 0;
+ return FALSE;
+ }
+ break;
+
+ case 0xfa: /* cli */
+ if (!v86_do_sti_cli) {
+ thread->recover = 0;
+ return (FALSE);
+ }
+
+ v86->flags &= ~EFL_IF;
+ /* disable simulated interrupts */
+ cli_count++;
+ break;
+
+ case 0xfb: /* sti */
+ if (!v86_do_sti_cli) {
+ thread->recover = 0;
+ return (FALSE);
+ }
+
+ if ((v86->flags & EFL_IF) == 0) {
+ if (v86_do_sti_immediate) {
+ v86->flags |= EFL_IF;
+ } else {
+ v86->flags |= V86_IF_PENDING;
+ regs->efl |= EFL_TF;
+ }
+ /* single step to set IF next inst. */
+ }
+ sti_count++;
+ break;
+
+ case 0x9c: /* pushf */
+ {
+ int flags;
+ vm_offset_t sp;
+ int size;
+
+ flags = regs->efl;
+ if ((v86->flags & EFL_IF) == 0)
+ flags &= ~EFL_IF;
+
+ if ((v86->flags & EFL_TF) == 0)
+ flags &= ~EFL_TF;
+ else flags |= EFL_TF;
+
+ sp = regs->uesp;
+ if (!addr_32)
+ sp &= 0xffff;
+ else if (sp > 0xffff)
+ goto stack_error;
+ size = (data_32) ? 4 : 2;
+ if (sp < size)
+ goto stack_error;
+ sp -= size;
+ if (copyout((char *)&flags,
+ (char *)Addr8086(regs->ss,sp),
+ size))
+ goto addr_error;
+ if (addr_32)
+ regs->uesp = sp;
+ else
+ regs->uesp = (regs->uesp & 0xffff0000) | sp;
+ break;
+ }
+
+ case 0x9d: /* popf */
+ {
+ vm_offset_t sp;
+ int nflags;
+
+ sp = regs->uesp;
+ if (!addr_32)
+ sp &= 0xffff;
+ else if (sp > 0xffff)
+ goto stack_error;
+
+ if (data_32) {
+ if (sp > 0xffff - sizeof(int))
+ goto stack_error;
+ nflags = *(int *)Addr8086(regs->ss,sp);
+ sp += sizeof(int);
+ }
+ else {
+ if (sp > 0xffff - sizeof(short))
+ goto stack_error;
+ nflags = *(unsigned short *)
+ Addr8086(regs->ss,sp);
+ sp += sizeof(short);
+ }
+ if (addr_32)
+ regs->uesp = sp;
+ else
+ regs->uesp = (regs->uesp & 0xffff0000) | sp;
+
+ if (v86->flags & V86_IRET_PENDING) {
+ v86->flags = nflags & (EFL_TF | EFL_IF);
+ v86->flags |= V86_IRET_PENDING;
+ } else {
+ v86->flags = nflags & (EFL_TF | EFL_IF);
+ }
+ regs->efl = (regs->efl & ~EFL_V86_SAFE)
+ | (nflags & EFL_V86_SAFE);
+ break;
+ }
+ case 0xcf: /* iret */
+ {
+ vm_offset_t sp;
+ int nflags;
+ int size;
+ union iret_struct iret_struct;
+
+ v86->flags &= ~V86_IRET_PENDING;
+ sp = regs->uesp;
+ if (!addr_32)
+ sp &= 0xffff;
+ else if (sp > 0xffff)
+ goto stack_error;
+
+ if (data_32) {
+ if (sp > 0xffff - sizeof(struct iret_32))
+ goto stack_error;
+ iret_struct.iret_32 =
+ *(struct iret_32 *) Addr8086(regs->ss,sp);
+ sp += sizeof(struct iret_32);
+ }
+ else {
+ if (sp > 0xffff - sizeof(struct iret_16))
+ goto stack_error;
+ iret_struct.iret_16 =
+ *(struct iret_16 *) Addr8086(regs->ss,sp);
+ sp += sizeof(struct iret_16);
+ }
+ if (addr_32)
+ regs->uesp = sp;
+ else
+ regs->uesp = (regs->uesp & 0xffff0000) | sp;
+
+ if (data_32) {
+ eip = iret_struct.iret_32.eip;
+ regs->cs = iret_struct.iret_32.cs & 0xffff;
+ nflags = iret_struct.iret_32.eflags;
+ }
+ else {
+ eip = iret_struct.iret_16.ip;
+ regs->cs = iret_struct.iret_16.cs;
+ nflags = iret_struct.iret_16.flags;
+ }
+
+ v86->flags = nflags & (EFL_TF | EFL_IF);
+ regs->efl = (regs->efl & ~EFL_V86_SAFE)
+ | (nflags & EFL_V86_SAFE);
+ break;
+ }
+ default:
+ /*
+ * Instruction not emulated here.
+ */
+ thread->recover = 0;
+ return FALSE;
+ }
+ break; /* exit from 'while TRUE' */
+ }
+ regs->eip = (regs->eip & 0xffff0000 | eip);
+ }
+ else {
+ /*
+ * Not a trap we handle.
+ */
+ thread->recover = 0;
+ return FALSE;
+ }
+
+ if ((v86->flags & EFL_IF) && ((v86->flags & V86_IRET_PENDING)==0)) {
+
+ struct v86_interrupt_table *int_table;
+ int int_count;
+ int vec;
+ int i;
+
+ int_table = (struct v86_interrupt_table *) v86->int_table;
+ int_count = v86->int_count;
+
+ vec = 0;
+ for (i = 0; i < int_count; int_table++, i++) {
+ if (!int_table->mask && int_table->count > 0) {
+ int_table->count--;
+ vec = int_table->vec;
+ break;
+ }
+ }
+ if (vec != 0) {
+ /*
+ * Take this interrupt
+ */
+ vm_offset_t sp;
+ struct iret_16 iret_16;
+ struct int_vec int_vec;
+
+ sp = regs->uesp & 0xffff;
+ if (sp < sizeof(struct iret_16))
+ goto stack_error;
+ sp -= sizeof(struct iret_16);
+ iret_16.ip = regs->eip;
+ iret_16.cs = regs->cs;
+ iret_16.flags = regs->efl & 0xFFFF;
+ if ((v86->flags & EFL_TF) == 0)
+ iret_16.flags &= ~EFL_TF;
+ else iret_16.flags |= EFL_TF;
+
+#ifdef gcc_1_36_worked
+ int_vec = ((struct int_vec *)0)[vec];
+#else
+ bcopy((char *) (sizeof(struct int_vec) * vec),
+ (char *)&int_vec,
+ sizeof (struct int_vec));
+#endif
+ if (copyout((char *)&iret_16,
+ (char *)Addr8086(regs->ss,sp),
+ sizeof(struct iret_16)))
+ goto addr_error;
+ regs->uesp = (regs->uesp & 0xFFFF0000) | (sp & 0xffff);
+ regs->eip = int_vec.ip;
+ regs->cs = int_vec.cs;
+ regs->efl &= ~EFL_TF;
+ v86->flags &= ~(EFL_IF | EFL_TF);
+ v86->flags |= V86_IRET_PENDING;
+ }
+ }
+
+ thread->recover = 0;
+ return TRUE;
+
+ /*
+ * On address error, report a page fault.
+ * XXX report GP fault - we don`t save
+ * the faulting address.
+ */
+ addr_error:
+ asm("addr_error:;");
+ thread->recover = 0;
+ return FALSE;
+
+ /*
+ * On stack address error, return stack fault (12).
+ */
+ stack_error:
+ thread->recover = 0;
+ regs->trapno = T_STACK_FAULT;
+ return FALSE;
+}
+
+/*
+ * Handle AST traps for i386.
+ * Check for delayed floating-point exception from
+ * AT-bus machines.
+ */
+void
+i386_astintr()
+{
+ int mycpu = cpu_number();
+
+ (void) splsched(); /* block interrupts to check reasons */
+ if (need_ast[mycpu] & AST_I386_FP) {
+ /*
+ * AST was for delayed floating-point exception -
+ * FP interrupt occured while in kernel.
+ * Turn off this AST reason and handle the FPU error.
+ */
+ ast_off(mycpu, AST_I386_FP);
+ (void) spl0();
+
+ fpexterrflt();
+ }
+ else {
+ /*
+ * Not an FPU trap. Handle the AST.
+ * Interrupts are still blocked.
+ */
+ ast_taken();
+ }
+}
+
+/*
+ * Handle exceptions for i386.
+ *
+ * If we are an AT bus machine, we must turn off the AST for a
+ * delayed floating-point exception.
+ *
+ * If we are providing floating-point emulation, we may have
+ * to retrieve the real register values from the floating point
+ * emulator.
+ */
+void
+i386_exception(exc, code, subcode)
+ int exc;
+ int code;
+ int subcode;
+{
+ spl_t s;
+
+ /*
+ * Turn off delayed FPU error handling.
+ */
+ s = splsched();
+ ast_off(cpu_number(), AST_I386_FP);
+ splx(s);
+
+#if FPE
+ fpe_exception_fixup(exc, code, subcode);
+#else
+ exception(exc, code, subcode);
+#endif
+ /*NOTREACHED*/
+}
+
+boolean_t
+check_io_fault(regs)
+ struct i386_saved_state *regs;
+{
+ int eip, opcode, io_port;
+ boolean_t data_16 = FALSE;
+
+ /*
+ * Get the instruction.
+ */
+ eip = regs->eip;
+
+ for (;;) {
+ opcode = inst_fetch(eip, regs->cs);
+ eip++;
+ switch (opcode) {
+ case 0x66: /* data-size prefix */
+ data_16 = TRUE;
+ continue;
+
+ case 0xf3: /* rep prefix */
+ case 0x26: /* es */
+ case 0x2e: /* cs */
+ case 0x36: /* ss */
+ case 0x3e: /* ds */
+ case 0x64: /* fs */
+ case 0x65: /* gs */
+ continue;
+
+ case 0xE4: /* inb imm */
+ case 0xE5: /* inl imm */
+ case 0xE6: /* outb imm */
+ case 0xE7: /* outl imm */
+ /* port is immediate byte */
+ io_port = inst_fetch(eip, regs->cs);
+ eip++;
+ break;
+
+ case 0xEC: /* inb dx */
+ case 0xED: /* inl dx */
+ case 0xEE: /* outb dx */
+ case 0xEF: /* outl dx */
+ case 0x6C: /* insb */
+ case 0x6D: /* insl */
+ case 0x6E: /* outsb */
+ case 0x6F: /* outsl */
+ /* port is in DX register */
+ io_port = regs->edx & 0xFFFF;
+ break;
+
+ default:
+ return FALSE;
+ }
+ break;
+ }
+
+ if (data_16)
+ opcode |= 0x6600; /* word IO */
+
+ switch (emulate_io(regs, opcode, io_port)) {
+ case EM_IO_DONE:
+ /* instruction executed */
+ regs->eip = eip;
+ return TRUE;
+
+ case EM_IO_RETRY:
+ /* port mapped, retry instruction */
+ return TRUE;
+
+ case EM_IO_ERROR:
+ /* port not mapped */
+ return FALSE;
+ }
+}
+
+#if MACH_PCSAMPLE > 0
+/*
+ * return saved state for interrupted user thread
+ */
+unsigned
+interrupted_pc(t)
+ thread_t t;
+{
+ register struct i386_saved_state *iss;
+
+ iss = USER_REGS(t);
+ return iss->eip;
+}
+#endif /* MACH_PCSAMPLE > 0*/
+
diff --git a/i386/i386/trap.h b/i386/i386/trap.h
new file mode 100644
index 00000000..f4dcbd57
--- /dev/null
+++ b/i386/i386/trap.h
@@ -0,0 +1,38 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_TRAP_H_
+#define _I386_TRAP_H_
+
+#include <mach/machine/trap.h>
+
+#ifndef ASSEMBLER
+
+char *trap_name(unsigned int trapnum);
+
+#endif !ASSEMBLER
+
+#endif _I386_TRAP_H_
diff --git a/i386/i386/tss.h b/i386/i386/tss.h
new file mode 100644
index 00000000..0d02f703
--- /dev/null
+++ b/i386/i386/tss.h
@@ -0,0 +1,76 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_TSS_H_
+#define _I386_TSS_H_
+
+#include <mach/inline.h>
+
+/*
+ * i386 Task State Segment
+ */
+struct i386_tss {
+ int back_link; /* segment number of previous task,
+ if nested */
+ int esp0; /* initial stack pointer ... */
+ int ss0; /* and segment for ring 0 */
+ int esp1; /* initial stack pointer ... */
+ int ss1; /* and segment for ring 1 */
+ int esp2; /* initial stack pointer ... */
+ int ss2; /* and segment for ring 2 */
+ int cr3; /* CR3 - page table directory
+ physical address */
+ int eip;
+ int eflags;
+ int eax;
+ int ecx;
+ int edx;
+ int ebx;
+ int esp; /* current stack pointer */
+ int ebp;
+ int esi;
+ int edi;
+ int es;
+ int cs;
+ int ss; /* current stack segment */
+ int ds;
+ int fs;
+ int gs;
+ int ldt; /* local descriptor table segment */
+ unsigned short trace_trap; /* trap on switch to this task */
+ unsigned short io_bit_map_offset;
+ /* offset to start of IO permission
+ bit map */
+};
+
+/* Load the current task register. */
+MACH_INLINE void
+ltr(unsigned short segment)
+{
+ __asm volatile("ltr %0" : : "r" (segment));
+}
+
+#endif /* _I386_TSS_H_ */
diff --git a/i386/i386/user_ldt.c b/i386/i386/user_ldt.c
new file mode 100644
index 00000000..71ca08da
--- /dev/null
+++ b/i386/i386/user_ldt.c
@@ -0,0 +1,389 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1994,1993,1992,1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * User LDT management.
+ * Each thread in a task may have its own LDT.
+ */
+
+#include <kern/kalloc.h>
+#include <kern/thread.h>
+
+#include <vm/vm_kern.h>
+
+#include <i386/seg.h>
+#include <i386/thread.h>
+#include <i386/user_ldt.h>
+#include "ldt.h"
+
+char acc_type[8][3] = {
+ /* code stack data */
+ { 0, 0, 1 }, /* data */
+ { 0, 1, 1 }, /* data, writable */
+ { 0, 0, 1 }, /* data, expand-down */
+ { 0, 1, 1 }, /* data, writable, expand-down */
+ { 1, 0, 0 }, /* code */
+ { 1, 0, 1 }, /* code, readable */
+ { 1, 0, 0 }, /* code, conforming */
+ { 1, 0, 1 }, /* code, readable, conforming */
+};
+
+boolean_t selector_check(thread, sel, type)
+ thread_t thread;
+ int sel;
+ int type; /* code, stack, data */
+{
+ struct user_ldt *ldt;
+ int access;
+
+ ldt = thread->pcb->ims.ldt;
+ if (ldt == 0) {
+ switch (type) {
+ case S_CODE:
+ return sel == USER_CS;
+ case S_STACK:
+ return sel == USER_DS;
+ case S_DATA:
+ return sel == 0 ||
+ sel == USER_CS ||
+ sel == USER_DS;
+ }
+ }
+
+ if (type != S_DATA && sel == 0)
+ return FALSE;
+ if ((sel & (SEL_LDT|SEL_PL)) != (SEL_LDT|SEL_PL_U)
+ || sel > ldt->desc.limit_low)
+ return FALSE;
+
+ access = ldt->ldt[sel_idx(sel)].access;
+
+ if ((access & (ACC_P|ACC_PL|ACC_TYPE_USER))
+ != (ACC_P|ACC_PL_U|ACC_TYPE_USER))
+ return FALSE;
+ /* present, pl == pl.user, not system */
+
+ return acc_type[(access & 0xe)>>1][type];
+}
+
+/*
+ * Add the descriptors to the LDT, starting with
+ * the descriptor for 'first_selector'.
+ */
+kern_return_t
+i386_set_ldt(thread, first_selector, desc_list, count, desc_list_inline)
+ thread_t thread;
+ int first_selector;
+ struct real_descriptor *desc_list;
+ unsigned int count;
+ boolean_t desc_list_inline;
+{
+ user_ldt_t new_ldt, old_ldt, cur_ldt;
+ struct real_descriptor *dp;
+ int i;
+ pcb_t pcb;
+ vm_size_t ldt_size_needed;
+ int first_desc = sel_idx(first_selector);
+ vm_map_copy_t old_copy_object;
+
+ if (thread == THREAD_NULL)
+ return KERN_INVALID_ARGUMENT;
+ if (first_desc < 0 || first_desc > 8191)
+ return KERN_INVALID_ARGUMENT;
+ if (first_desc + count >= 8192)
+ return KERN_INVALID_ARGUMENT;
+
+ /*
+ * If desc_list is not inline, it is in copyin form.
+ * We must copy it out to the kernel map, and wire
+ * it down (we touch it while the PCB is locked).
+ *
+ * We make a copy of the copyin object, and clear
+ * out the old one, so that returning KERN_INVALID_ARGUMENT
+ * will not try to deallocate the data twice.
+ */
+ if (!desc_list_inline) {
+ kern_return_t kr;
+ vm_offset_t dst_addr;
+
+ old_copy_object = (vm_map_copy_t) desc_list;
+
+ kr = vm_map_copyout(ipc_kernel_map, &dst_addr,
+ vm_map_copy_copy(old_copy_object));
+ if (kr != KERN_SUCCESS)
+ return kr;
+
+ (void) vm_map_pageable(ipc_kernel_map,
+ dst_addr,
+ dst_addr + count * sizeof(struct real_descriptor),
+ VM_PROT_READ|VM_PROT_WRITE);
+ desc_list = (struct real_descriptor *)dst_addr;
+ }
+
+ for (i = 0, dp = desc_list;
+ i < count;
+ i++, dp++)
+ {
+ switch (dp->access & ~ACC_A) {
+ case 0:
+ case ACC_P:
+ /* valid empty descriptor */
+ break;
+ case ACC_P | ACC_CALL_GATE:
+ /* Mach kernel call */
+ *dp = *(struct real_descriptor *)
+ &ldt[sel_idx(USER_SCALL)];
+ break;
+ case ACC_P | ACC_PL_U | ACC_DATA:
+ case ACC_P | ACC_PL_U | ACC_DATA_W:
+ case ACC_P | ACC_PL_U | ACC_DATA_E:
+ case ACC_P | ACC_PL_U | ACC_DATA_EW:
+ case ACC_P | ACC_PL_U | ACC_CODE:
+ case ACC_P | ACC_PL_U | ACC_CODE_R:
+ case ACC_P | ACC_PL_U | ACC_CODE_C:
+ case ACC_P | ACC_PL_U | ACC_CODE_CR:
+ case ACC_P | ACC_PL_U | ACC_CALL_GATE_16:
+ case ACC_P | ACC_PL_U | ACC_CALL_GATE:
+ break;
+ default:
+ return KERN_INVALID_ARGUMENT;
+ }
+ }
+ ldt_size_needed = sizeof(struct real_descriptor)
+ * (first_desc + count - 1);
+
+ pcb = thread->pcb;
+ old_ldt = 0; /* the one to throw away */
+ new_ldt = 0; /* the one to allocate */
+ Retry:
+ simple_lock(&pcb->lock);
+ cur_ldt = pcb->ims.ldt;
+ if (cur_ldt == 0 ||
+ cur_ldt->desc.limit_low + 1 < ldt_size_needed)
+ {
+ /*
+ * No current LDT, or not big enough
+ */
+ if (new_ldt == 0) {
+ simple_unlock(&pcb->lock);
+
+ new_ldt = (user_ldt_t)
+ kalloc(ldt_size_needed
+ + sizeof(struct real_descriptor));
+ /*
+ * Build a descriptor that describes the
+ * LDT itself
+ */
+ {
+ vm_offset_t ldt_base;
+
+ ldt_base = (vm_offset_t) &new_ldt->ldt[0];
+
+ new_ldt->desc.limit_low = ldt_size_needed - 1;
+ new_ldt->desc.limit_high = 0;
+ new_ldt->desc.base_low = ldt_base & 0xffff;
+ new_ldt->desc.base_med = (ldt_base >> 16) & 0xff;
+ new_ldt->desc.base_high = ldt_base >> 24;
+ new_ldt->desc.access = ACC_P | ACC_LDT;
+ new_ldt->desc.granularity = 0;
+ }
+
+ goto Retry;
+ }
+
+ /*
+ * Have new LDT. Copy descriptors from current to new.
+ */
+ if (cur_ldt)
+ bcopy((char *) &cur_ldt->ldt[0],
+ (char *) &new_ldt->ldt[0],
+ cur_ldt->desc.limit_low + 1);
+
+ old_ldt = cur_ldt; /* discard old LDT */
+ cur_ldt = new_ldt; /* use new LDT from now on */
+ new_ldt = 0; /* keep new LDT */
+
+ pcb->ims.ldt = cur_ldt; /* set LDT for thread */
+ }
+
+ /*
+ * Install new descriptors.
+ */
+ bcopy((char *) desc_list,
+ (char *) &cur_ldt->ldt[first_desc],
+ count * sizeof(struct real_descriptor));
+
+ simple_unlock(&pcb->lock);
+
+ /*
+ * Discard old LDT if it was replaced
+ */
+ if (old_ldt)
+ kfree((vm_offset_t)old_ldt,
+ old_ldt->desc.limit_low + 1
+ + sizeof(struct real_descriptor));
+
+ /*
+ * Discard new LDT if it was not used
+ */
+ if (new_ldt)
+ kfree((vm_offset_t)new_ldt,
+ new_ldt->desc.limit_low + 1
+ + sizeof(struct real_descriptor));
+
+ /*
+ * Free the descriptor list, if it was
+ * out-of-line. Also discard the original
+ * copy object for it.
+ */
+ if (!desc_list_inline) {
+ (void) kmem_free(ipc_kernel_map,
+ (vm_offset_t) desc_list,
+ count * sizeof(struct real_descriptor));
+ vm_map_copy_discard(old_copy_object);
+ }
+
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+i386_get_ldt(thread, first_selector, selector_count, desc_list, count)
+ thread_t thread;
+ int first_selector;
+ int selector_count; /* number wanted */
+ struct real_descriptor **desc_list; /* in/out */
+ unsigned int *count; /* in/out */
+{
+ struct user_ldt *user_ldt;
+ pcb_t pcb = thread->pcb;
+ int first_desc = sel_idx(first_selector);
+ unsigned int ldt_count;
+ vm_size_t ldt_size;
+ vm_size_t size, size_needed;
+ vm_offset_t addr;
+
+ if (thread == THREAD_NULL)
+ return KERN_INVALID_ARGUMENT;
+ if (first_desc < 0 || first_desc > 8191)
+ return KERN_INVALID_ARGUMENT;
+ if (first_desc + selector_count >= 8192)
+ return KERN_INVALID_ARGUMENT;
+
+ addr = 0;
+ size = 0;
+
+ for (;;) {
+ simple_lock(&pcb->lock);
+ user_ldt = pcb->ims.ldt;
+ if (user_ldt == 0) {
+ simple_unlock(&pcb->lock);
+ if (addr)
+ kmem_free(ipc_kernel_map, addr, size);
+ *count = 0;
+ return KERN_SUCCESS;
+ }
+
+ /*
+ * Find how many descriptors we should return.
+ */
+ ldt_count = (user_ldt->desc.limit_low + 1) /
+ sizeof (struct real_descriptor);
+ ldt_count -= first_desc;
+ if (ldt_count > selector_count)
+ ldt_count = selector_count;
+
+ ldt_size = ldt_count * sizeof(struct real_descriptor);
+
+ /*
+ * Do we have the memory we need?
+ */
+ if (ldt_count <= *count)
+ break; /* fits in-line */
+
+ size_needed = round_page(ldt_size);
+ if (size_needed <= size)
+ break;
+
+ /*
+ * Unlock the pcb and allocate more memory
+ */
+ simple_unlock(&pcb->lock);
+
+ if (size != 0)
+ kmem_free(ipc_kernel_map, addr, size);
+
+ size = size_needed;
+
+ if (kmem_alloc(ipc_kernel_map, &addr, size)
+ != KERN_SUCCESS)
+ return KERN_RESOURCE_SHORTAGE;
+ }
+
+ /*
+ * copy out the descriptors
+ */
+ bcopy((char *)&user_ldt[first_desc],
+ (char *)*desc_list,
+ ldt_size);
+ *count = ldt_count;
+ simple_unlock(&pcb->lock);
+
+ if (addr) {
+ vm_size_t size_used, size_left;
+ vm_map_copy_t memory;
+
+ /*
+ * Free any unused memory beyond the end of the last page used
+ */
+ size_used = round_page(ldt_size);
+ if (size_used != size)
+ kmem_free(ipc_kernel_map,
+ addr + size_used, size - size_used);
+
+ /*
+ * Zero the remainder of the page being returned.
+ */
+ size_left = size_used - ldt_size;
+ if (size_left > 0)
+ bzero((char *)addr + ldt_size, size_left);
+
+ /*
+ * Make memory into copyin form - this unwires it.
+ */
+ (void) vm_map_copyin(ipc_kernel_map, addr, size_used, TRUE, &memory);
+ *desc_list = (struct real_descriptor *)memory;
+ }
+
+ return KERN_SUCCESS;
+}
+
+void
+user_ldt_free(user_ldt)
+ user_ldt_t user_ldt;
+{
+ kfree((vm_offset_t)user_ldt,
+ user_ldt->desc.limit_low + 1
+ + sizeof(struct real_descriptor));
+}
diff --git a/i386/i386/user_ldt.h b/i386/i386/user_ldt.h
new file mode 100644
index 00000000..9267ac7e
--- /dev/null
+++ b/i386/i386/user_ldt.h
@@ -0,0 +1,55 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _I386_USER_LDT_H_
+#define _I386_USER_LDT_H_
+
+/*
+ * User LDT management.
+ *
+ * Each thread in a task may have its own LDT.
+ */
+
+#include <i386/seg.h>
+
+struct user_ldt {
+ struct real_descriptor desc; /* descriptor for self */
+ struct real_descriptor ldt[1]; /* descriptor table (variable) */
+};
+typedef struct user_ldt * user_ldt_t;
+
+/*
+ * Check code/stack/data selector values against LDT if present.
+ */
+#define S_CODE 0 /* code segment */
+#define S_STACK 1 /* stack segment */
+#define S_DATA 2 /* data segment */
+
+extern boolean_t selector_check(/* thread_t thread,
+ int sel,
+ int type */);
+
+#endif /* _I386_USER_LDT_H_ */
diff --git a/i386/i386/vm_param.h b/i386/i386/vm_param.h
new file mode 100644
index 00000000..30e9418e
--- /dev/null
+++ b/i386/i386/vm_param.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+#ifndef _I386_KERNEL_I386_VM_PARAM_
+#define _I386_KERNEL_I386_VM_PARAM_
+
+/* XXX use xu/vm_param.h */
+#include <mach/vm_param.h>
+
+/* The kernel address space is 1GB, starting at virtual address 0. */
+#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t) 0x00000000)
+#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t) 0x40000000)
+
+/* The kernel virtual address space is actually located
+ at high linear addresses.
+ This is the kernel address range in linear addresses. */
+#define LINEAR_MIN_KERNEL_ADDRESS ((vm_offset_t) 0xc0000000)
+#define LINEAR_MAX_KERNEL_ADDRESS ((vm_offset_t) 0xffffffff)
+
+#define KERNEL_STACK_SIZE (1*I386_PGBYTES)
+#define INTSTACK_SIZE (1*I386_PGBYTES)
+ /* interrupt stack size */
+
+/*
+ * Conversion between 80386 pages and VM pages
+ */
+
+#define trunc_i386_to_vm(p) (atop(trunc_page(i386_ptob(p))))
+#define round_i386_to_vm(p) (atop(round_page(i386_ptob(p))))
+#define vm_to_i386(p) (i386_btop(ptoa(p)))
+
+/*
+ * Physical memory is direct-mapped to virtual memory
+ * starting at virtual address phys_mem_va.
+ */
+extern vm_offset_t phys_mem_va;
+#define phystokv(a) ((vm_offset_t)(a) + phys_mem_va)
+
+/*
+ * Kernel virtual memory is actually at 0xc0000000 in linear addresses.
+ */
+#define kvtolin(a) ((vm_offset_t)(a) + LINEAR_MIN_KERNEL_ADDRESS)
+#define lintokv(a) ((vm_offset_t)(a) - LINEAR_MIN_KERNEL_ADDRESS)
+
+#endif _I386_KERNEL_I386_VM_PARAM_
diff --git a/i386/i386/vm_tuning.h b/i386/i386/vm_tuning.h
new file mode 100644
index 00000000..a5091fb7
--- /dev/null
+++ b/i386/i386/vm_tuning.h
@@ -0,0 +1,35 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * File: i386/vm_tuning.h
+ *
+ * VM tuning parameters for the i386 (without reference bits).
+ */
+
+#ifndef _I386_VM_TUNING_H_
+#define _I386_VM_TUNING_H_
+
+#endif _I386_VM_TUNING_H_
diff --git a/i386/i386/xpr.h b/i386/i386/xpr.h
new file mode 100644
index 00000000..19ef026a
--- /dev/null
+++ b/i386/i386/xpr.h
@@ -0,0 +1,32 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * File: xpr.h
+ *
+ * Machine dependent module for the XPR tracing facility.
+ */
+
+#define XPR_TIMESTAMP (0)
diff --git a/i386/i386/zalloc.h b/i386/i386/zalloc.h
new file mode 100644
index 00000000..bf7cf6b2
--- /dev/null
+++ b/i386/i386/zalloc.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 1996-1994 The University of Utah and
+ * the Computer Systems Laboratory (CSL). All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Utah $Hdr: zalloc.h 1.4 94/12/16$
+ * Author: Bryan Ford
+ */
+
+#ifndef _I386_ZALLOC_H_
+#define _I386_ZALLOC_H_
+
+#include <kern/zalloc.h>
+
+#endif /* _I386_ZALLOC_H_ */