summaryrefslogtreecommitdiff
path: root/i386/pc/rv86
diff options
context:
space:
mode:
Diffstat (limited to 'i386/pc/rv86')
-rw-r--r--i386/pc/rv86/config.h29
-rw-r--r--i386/pc/rv86/gdt_sels.h60
-rw-r--r--i386/pc/rv86/idt_irq_init.c40
-rw-r--r--i386/pc/rv86/rv86_real_int.c276
-rw-r--r--i386/pc/rv86/rv86_real_int_asm.S119
-rw-r--r--i386/pc/rv86/rv86_reflect_irq.S113
-rw-r--r--i386/pc/rv86/rv86_trap_handler.S167
-rw-r--r--i386/pc/rv86/trap_handler.S39
8 files changed, 843 insertions, 0 deletions
diff --git a/i386/pc/rv86/config.h b/i386/pc/rv86/config.h
new file mode 100644
index 0000000..5f971ce
--- /dev/null
+++ b/i386/pc/rv86/config.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 1995 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_next "config.h"
+
+#ifndef ENABLE_REAL_TSS
+#define ENABLE_REAL_TSS
+#endif
+
diff --git a/i386/pc/rv86/gdt_sels.h b/i386/pc/rv86/gdt_sels.h
new file mode 100644
index 0000000..89a13c7
--- /dev/null
+++ b/i386/pc/rv86/gdt_sels.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1995-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_next "gdt_sels.h"
+
+/* This is a special TSS with a full IO bitmap
+ that allows access to all I/O ports in v86 mode.
+ It's used for making calls to the real-mode BIOS (or DOS). */
+gdt_sel(RV86_TSS)
+
+/*
+ * Copyright (c) 1995-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_next "gdt_sels.h"
+
+/* This is a special TSS with a full IO bitmap
+ that allows access to all I/O ports in v86 mode.
+ It's used for making calls to the real-mode BIOS (or DOS). */
+gdt_sel(RV86_TSS)
+
diff --git a/i386/pc/rv86/idt_irq_init.c b/i386/pc/rv86/idt_irq_init.c
new file mode 100644
index 0000000..f46882a
--- /dev/null
+++ b/i386/pc/rv86/idt_irq_init.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1995 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 "cpu.h"
+#include "idt.h"
+
+void idt_irq_init()
+{
+ int i;
+
+#define irq(pic,picnum,irqnum) \
+ { extern void rv86_reflect_irq##irqnum(); \
+ fill_idt_gate(&cpu[0], irq_##pic##_base + picnum, \
+ (vm_offset_t)rv86_reflect_irq##irqnum, KERNEL_CS, \
+ ACC_PL_K|ACC_INTR_GATE); \
+ }
+#include "irq_list.h"
+#undef irq
+}
+
diff --git a/i386/pc/rv86/rv86_real_int.c b/i386/pc/rv86/rv86_real_int.c
new file mode 100644
index 0000000..d9c35b6
--- /dev/null
+++ b/i386/pc/rv86/rv86_real_int.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 1995-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 <mach/machine/seg.h>
+#include <mach/machine/proc_reg.h>
+#include <mach/machine/far_ptr.h>
+#include <mach/machine/eflags.h>
+
+#include "vm_param.h"
+#include "real.h"
+#include "real_tss.h"
+#include "cpu.h"
+#include "debug.h"
+
+
+/*
+
+ There seem to be three main ways to handle v86 mode:
+
+ * The v86 environment is just an extension of the normal kernel environment:
+ you can switch to and from v86 mode just as you can change any other processor state.
+ You always keep running on the separate "logical" stack,
+ which is the kernel stack when running in protected mode,
+ or the user stack when running in v86 mode.
+ When in v86 mode, the "actual" kernel stack is just a stub
+ big enough to switch back to the "normal" kernel stack,
+ which was being used as the user stack while running in v86 mode.
+ Thus, v86 and protected-mode "segments" of stack data
+ can be interleaved together on the same logical stack.
+
+ - To make a real int call from kernel pmode,
+ switch to v86 mode and execute an int instruction,
+ then switch back to protected mode.
+
+ - To reflect an interrupt to v86 mode:
+
+ > If the processor was running in v86 mode,
+ just adjust the kernel and user stacks
+ to emulate a real-mode interrupt, and return.
+
+ > If the processor was running in pmode,
+ switch to v86 mode and re-trigger the interrupt
+ with a software int instruction.
+
+ - To handle an interrupt in pmode:
+
+ > If the processor was running in v86 mode,
+ switch from the stub stack to the user stack that was in use
+ (could be different from the stack we set originally,
+ because BIOS/DOS code might have switched stacks!),
+ call the interrupt handler, switch back, and return.
+
+ > If the processor was running in pmode,
+ just call the interrupt handler and return.
+
+ This method only works if the whole "kernel" is <64KB
+ and generally compatible with real-mode execution.
+ This is the model my DOS extender currently uses.
+
+ One major disadvantage of this method
+ is that interrupt handlers can't run "general" protected-mode code,
+ such as typical code compiled by GCC.
+ This is because, if an interrupt occurs while in v86 mode,
+ the v86-mode ss:sp may point basically anywhere in the low 1MB,
+ and it therefore it can't be used directly as a pmode stack;
+ and the only other stack available is the miniscule stub stack.
+ Since "general" protected-mode code expects a full-size stack
+ with an SS equal to the normal protected-mode DS,
+ neither of these available stacks will suffice.
+ It is impossible to switch back to the original kernel stack
+ because arbitrary DOS or BIOS code might have switched from it
+ to a different stack somewhere else in the low 1MB,
+ and we have no way of telling where the SP was when that happened.
+ The upshot is that interrupt handlers must be extremely simple;
+ in MOSS, all they do is post a signal to "the process,"
+ and return immediately without actually handling the interrupt.
+
+ * The v86 environment is a separate "task" with its own user and kernel stacks;
+ you switch back and forth as if between multiple ordinary tasks,
+ the tasks can preempt each other, go idle waiting for events, etc.
+
+ - To make a real int call from kernel pmode,
+ the task making the call essentially does a synchronous IPC to the v86 task.
+ If the v86 task is busy with another request or a reflected interrupt,
+ the calling task will go idle until the v86 task is available.
+
+ - Reflecting an interrupt to v86 mode
+ basically amounts to sending a Unix-like "signal" to the v86 task:
+
+ > If the processor was running in the v86 task,
+ just adjust the kernel and user stacks
+ to emulate a real-mode interrupt, and return.
+
+ > If the processor was running in a protected-mode task
+ (or another v86-mode task),
+ post a signal to the v86 task, wake it up if it's asleep,
+ and invoke the scheduler to switch to the v86 task
+ if it has a higher priority than the currently running task.
+
+ - To handle an interrupt in pmode,
+ just call the interrupt handler and return.
+ It doesn't matter whether the interrupt was from v86 or pmode,
+ because the kernel stacks look the same in either case.
+
+ One big problem with this method is that if interrupts are to be handled in v86 mode,
+ all the typical problems of handling interrupts in user-mode tasks pop up.
+ In particular, an interrupt can now cause preemption,
+ so this will break an interruptible but nonpreemptible environment.
+ (The problem is not that the interrupted task is "preempted"
+ to switch temporarily to the v86 task to handle the interrupt;
+ the problem is that when the v86 task is done handling the interrupt,
+ the scheduler will be invoked and some task other than the interrupted task may be run.)
+
+ Of course, this is undoubtedly the right solution
+ if that's the interrupt model the OS is using anyway
+ (i.e. if the OS already supports user-level protected-mode interrupts).
+
+ * A bastardization of the two above approaches:
+ treat the v86 environment as a separate "task",
+ but a special one that doesn't behave at all like other tasks.
+ The v86 "task" in this case is more of an "interrupt co-stack"
+ that grows and shrinks alongside the normal interrupt stack
+ (or the current kernel stack, if interrupts are handled on the kernel stack).
+ Interrupts and real calls can cause switches between these two interrupt stacks,
+ but they can't cause preemption in the normal sense.
+ The route taken while building the stacks is exactly the opposite
+ the route taken while tearing it down.
+
+ Now two "kernel stack pointers" have to be maintained all the time instead of one.
+ When running in protected mode:
+
+ - The ESP register contains the pmode stack pointer.
+ - Some global variable contains the v86 stack pointer.
+
+ When running in v86 mode:
+
+ - The ESP register contains the v86 stack pointer.
+ (Note that BIOS/DOS code can switch stacks,
+ so at any given time it may point practically anywhere!)
+ - The current tss's esp0 contains the pmode stack pointer.
+
+ Whenever a switch is made, a stack frame is placed on the new co-stack
+ indicating that the switch was performed.
+
+ - To make a real int call from kernel pmode,
+ build a real-mode interrupt stack frame on the v86 interrupt stack,
+ build a v86-mode trap stack frame on the pmode stack,
+ set the tss's esp0 to point to the end of that stack frame,
+ and iret from it.
+ Then when the magic "done-with-real-call" int instruction is hit,
+ the pmode interrupt handler will see it
+ and know to simply destroy the v86 trap stack on the pmode stack.
+
+ - Handling an interrupt can always be thought of as going "through" pmode:
+ switching from the v86 stack to the pmode stack
+ if the processor was in v86 mode when the interrupt was taken,
+ and switching from the pmode stack back to the v86 stack as described above
+ if the interrupt is to be reflected to v86 mode.
+
+ Of course, optimized paths are possible:
+
+ - To reflect an interrupt to v86 mode:
+
+ > If the processor was running in v86 mode,
+ just adjust the kernel and user stack frames and return.
+
+ > If the processor was running in pmode,
+ do as described above for explicit real int calls.
+
+ - To handle an interrupt in pmode:
+
+ > If the processor was running in v86 mode,
+ switch to the pmode stack,
+ stash the old v86 stack pointer variable on the pmode stack,
+ and set the v86 stack pointer variable to the new location.
+ Call the interrupt handler,
+ then tear down everything and return to v86 mode.
+
+ Observation:
+ In the first and third models,
+ explicit real int calls are entirely symmetrical
+ to hardware interrupts from pmode to v86 mode.
+ This is valid because of the interruptible but nonpreemptible model:
+ no scheduling is involved, and the stack(s) will always be torn down
+ in exactly the opposite order in which they were built up.
+ In the second model,
+ explicit real calls are quite different,
+ because the BIOS is interruptible but nonpreemptible:
+ you can reflect an interrupt into the v86 task at any time,
+ but you can only make an explicit request to that task when it's ready
+ (i.e. no other requests or interrupts are outstanding).
+
+*/
+
+
+
+#define RV86_USTACK_SIZE 1024
+
+vm_offset_t rv86_ustack_pa;
+vm_offset_t rv86_return_int_pa;
+struct far_pointer_32 rv86_usp;
+struct far_pointer_16 rv86_rp;
+
+void rv86_real_int(int intnum, struct real_call_data *rcd)
+{
+ unsigned short old_tr;
+ unsigned int old_eflags;
+
+ /* If this is the first time this routine is being called,
+ initialize the kernel stack. */
+ if (!rv86_ustack_pa)
+ {
+ rv86_ustack_pa = 0xa0000 - RV86_USTACK_SIZE; /* XXX */
+
+ assert(rv86_ustack_pa < 0x100000);
+
+ /* Use the top two bytes of the ustack for an 'int $0xff' instruction. */
+ rv86_return_int_pa = rv86_ustack_pa + RV86_USTACK_SIZE - 2;
+ *(short*)phystokv(rv86_return_int_pa) = 0xffcd;
+
+ /* Set up the v86 stack pointer. */
+ rv86_usp.seg = rv86_rp.seg = rv86_ustack_pa >> 4;
+ rv86_usp.ofs = rv86_rp.ofs = (rv86_ustack_pa & 0xf) + RV86_USTACK_SIZE - 2;
+
+ /* Pre-allocate a real-mode interrupt stack frame. */
+ rv86_usp.ofs -= 6;
+ }
+
+ /* Make sure interrupts are disabled. */
+ old_eflags = get_eflags();
+
+ /* Switch to the TSS to use in v86 mode. */
+ old_tr = get_tr();
+ cpu[0].tables.gdt[REAL_TSS_IDX].access &= ~ACC_TSS_BUSY;
+ set_tr(REAL_TSS);
+
+ asm volatile("
+ pushl %%ebp
+ pushl %%eax
+ call rv86_real_int_asm
+ popl %%eax
+ popl %%ebp
+ " :
+ : "a" (rcd), "S" (intnum)
+ : "eax", "ebx", "ecx", "edx", "esi", "edi");
+
+ /* Switch to the original TSS. */
+ cpu[0].tables.gdt[old_tr/8].access &= ~ACC_TSS_BUSY;
+ set_tr(old_tr);
+
+ /* Restore the original processor flags. */
+ set_eflags(old_eflags);
+}
+
+void (*real_int)(int intnum, struct real_call_data *rcd) = rv86_real_int;
+
diff --git a/i386/pc/rv86/rv86_real_int_asm.S b/i386/pc/rv86/rv86_real_int_asm.S
new file mode 100644
index 0000000..54b1b9b
--- /dev/null
+++ b/i386/pc/rv86/rv86_real_int_asm.S
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1995 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 <mach/machine/asm.h>
+#include <mach/machine/eflags.h>
+
+#include "trap.h"
+#include "i386_asm.h"
+#include "pc_asm.h"
+#include "trap_asm.h"
+
+ .text
+ .globl rv86_real_int_asm
+rv86_real_int_asm:
+
+ /* Stash our protected-mode stack pointer. */
+ movl %esp,EXT(real_tss)+TSS_ESP0
+
+ /* Load the linear/physical-address data segment into ES,
+ for easy access to real-mode memory. */
+ movl $LINEAR_DS,%edx
+ movw %dx,%es
+
+ /* Find the physical address of the real-mode interrupt stack (es:ebx).
+ A 6-byte stack frame has already been allocated on it. */
+ movl EXT(rv86_usp)+4,%ebx
+ shll $4,%ebx
+ addl EXT(rv86_usp),%ebx
+
+ /* Store the magic return pointer into the real-mode interrupt stack frame. */
+ movl EXT(rv86_rp),%edx
+ movl %edx,%es:(%ebx)
+ movw RCD_FLAGS(%eax),%dx
+ movw %dx,%es:4(%ebx)
+
+ /* Find the address of the real mode interrupt vector (es:esi). */
+ shll $2,%esi
+
+ /* Build the v86 trap frame. */
+ xorl %edx,%edx
+ movw RCD_GS(%eax),%dx
+ pushl %edx
+ movw RCD_FS(%eax),%dx
+ pushl %edx
+ movw RCD_DS(%eax),%dx
+ pushl %edx
+ movw RCD_ES(%eax),%dx
+ pushl %edx
+ pushl EXT(rv86_usp)+4
+ pushl EXT(rv86_usp)
+ movl $EFL_VM+EFL_IOPL_USER,%ecx
+ orw RCD_FLAGS(%eax),%cx
+ andl $-1-EFL_IF-EFL_TF,%ecx
+ pushl %ecx
+ movw %es:2(%esi),%edx
+ pushl %edx
+ movw %es:(%esi),%edx
+ pushl %edx
+
+ /* Load the requested register state. */
+ movl RCD_EDI(%eax),%edi
+ movl RCD_ESI(%eax),%esi
+ movl RCD_EBP(%eax),%ebp
+ movl RCD_EBX(%eax),%ebx
+ movl RCD_EDX(%eax),%edx
+ movl RCD_ECX(%eax),%ecx
+ movl RCD_EAX(%eax),%eax
+
+ /* Drop into v86 mode. */
+ iret
+
+ENTRY(rv86_return)
+
+ /* Restore the kernel segment registers. */
+ movw %ss,%ax
+ movw %ax,%ds
+ movw %ax,%es
+
+ /* Retrieve the real_call_data pointer from rv86_real_int_asm's stack frame. */
+ movl TR_V86SIZE+4(%esp),%eax
+
+ /* Stash the final register state. */
+ movl TR_EDI(%esp),%edx; movl %edx,RCD_EDI(%eax)
+ movl TR_ESI(%esp),%edx; movl %edx,RCD_ESI(%eax)
+ movl TR_EBP(%esp),%edx; movl %edx,RCD_EBP(%eax)
+ movl TR_EBX(%esp),%edx; movl %edx,RCD_EBX(%eax)
+ movl TR_EDX(%esp),%edx; movl %edx,RCD_EDX(%eax)
+ movl TR_ECX(%esp),%edx; movl %edx,RCD_ECX(%eax)
+ movl TR_EAX(%esp),%edx; movl %edx,RCD_EAX(%eax)
+ movl TR_EFLAGS(%esp),%edx; movw %dx,RCD_FLAGS(%eax)
+ movl TR_V86_ES(%esp),%edx; movw %dx,RCD_ES(%eax)
+ movl TR_V86_DS(%esp),%edx; movw %dx,RCD_DS(%eax)
+ movl TR_V86_FS(%esp),%edx; movw %dx,RCD_FS(%eax)
+ movl TR_V86_GS(%esp),%edx; movw %dx,RCD_GS(%eax)
+
+ /* Return from the call to rv86_real_int_asm. */
+ lea TR_V86SIZE(%esp),%esp
+ ret
+
diff --git a/i386/pc/rv86/rv86_reflect_irq.S b/i386/pc/rv86/rv86_reflect_irq.S
new file mode 100644
index 0000000..5d68fae
--- /dev/null
+++ b/i386/pc/rv86/rv86_reflect_irq.S
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1995 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 <mach/machine/asm.h>
+#include <mach/machine/eflags.h>
+
+#include "trap.h"
+#include "trap_asm.h"
+#include "pc_asm.h"
+#include "i386_asm.h"
+
+/*
+ * Define a set of interrupt handlers to reflect interrupts to v86 mode.
+ */
+
+ .text
+
+#define master_base 0x08
+#define slave_base 0x70
+
+#define irq(pic,picnum,irqnum) \
+ENTRY(rv86_reflect_irq##irqnum) ;\
+ pushl $pic##_base+picnum ;\
+ pushl $0x80000000+irqnum /* (for debug) */ ;\
+ jmp allintrs
+
+#include "irq_list.h"
+
+
+allintrs:
+ pusha
+ pushl %ds
+ pushl %es
+ pushl %fs
+ pushl %gs
+
+ /* Load the normal kernel segment registers. */
+ movw %ss,%ax
+ movw %ax,%ds
+ movw %ax,%es
+
+ /* See if we came from v86 mode. */
+ testl $EFL_VM,TR_EFLAGS(%esp)
+ jnz int_from_v86
+
+ movl TR_ERR(%esp),%eax
+ pushl $dummy_rcd
+ pushl %eax
+ call EXT(rv86_real_int)
+ addl $2*4,%esp
+
+ popl %gs
+ popl %fs
+ popl %es
+ popl %ds
+ popa
+ addl $2*4,%esp
+ iret
+
+int_from_v86:
+
+ /* Save the v86 stack pointer before handling the interrupt.
+ We need this in order to handle recursive reflected interrupts
+ possibly interspersed with protected-mode interrupts. */
+ movl EXT(rv86_usp),%esi
+ movl EXT(rv86_usp)+4,%edi
+ movl EXT(real_tss)+TSS_ESP0,%ebx
+
+ movl TR_ESP(%esp),%eax
+ subw $6,%ax /* allocate a real-mode interrupt stack frame. */
+ movl %eax,EXT(rv86_usp)
+ movl TR_SS(%esp),%eax
+ movw %ax,EXT(rv86_usp)+4
+
+ movl TR_ERR(%esp),%eax
+ pushl $dummy_rcd
+ pushl %eax
+ call EXT(rv86_real_int)
+ addl $2*4,%esp
+
+ movl %esi,EXT(rv86_usp)
+ movl %edi,EXT(rv86_usp)+4
+ movl %ebx,EXT(real_tss)+TSS_ESP0
+
+ addl $4*4,%esp
+ popa
+ addl $2*4,%esp
+ iret
+
+ /* Dummy real_call_data structure (always all zero)
+ to use when reflecting hardware interrupts. */
+ .comm dummy_rcd,RCD_SIZE
+
diff --git a/i386/pc/rv86/rv86_trap_handler.S b/i386/pc/rv86/rv86_trap_handler.S
new file mode 100644
index 0000000..793f6b6
--- /dev/null
+++ b/i386/pc/rv86/rv86_trap_handler.S
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 1995-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 <mach/machine/asm.h>
+#include <mach/machine/eflags.h>
+
+#include "i386_asm.h"
+#include "trap.h"
+#include "trap_asm.h"
+
+ .text
+
+ENTRY(rv86_trap_handler)
+ cmpl $T_GENERAL_PROTECTION,TR_TRAPNO(%esp)
+ jz gpf_from_v86
+
+ UNEXPECTED_TRAP
+
+gpf_from_v86:
+
+ /* Load the linear/physical-address data segment,
+ for easy access to real-mode memory. */
+ movl $LINEAR_DS,%eax
+ movw %ax,%ds
+
+ /* Find the physical address of the trapping instruction (ebx). */
+ movzwl TR_CS(%esp),%ebx
+ shll $4,%ebx
+ addl TR_EIP(%esp),%ebx
+
+ /* See if we're just trying to get out of v86 mode. */
+ cmpl %ss:EXT(rv86_return_int_pa),%ebx
+ je EXT(rv86_return)
+
+ /* Check the instruction (al). */
+ movb (%ebx),%al
+ cmpb $0xcd,%al
+ je gpf_int_n
+
+ UNEXPECTED_TRAP
+
+
+gpf_int_n:
+
+ /* Bump the ip past the int instruction. */
+ addw $2,TR_EIP(%esp)
+
+ /* Find the real mode interrupt vector number (esi). */
+ movzbl 1(%ebx),%esi
+
+ /* See if it's a copy-extended-memory interrupt request;
+ if so, just handle it here. */
+ cmpl $0x15,%esi
+ jne 1f
+ cmpb $0x87,TR_EAX+1(%esp)
+ je copy_ext_mem
+1:
+
+ /* XXX The stuff down here is essentially the same as in moss. */
+
+reflect_v86_intr:
+
+ /* Find the address of the real mode interrupt vector (esi). */
+ shll $2,%esi
+
+ /* Make room for the real-mode interrupt stack frame. */
+ subw $6,TR_ESP(%esp)
+
+ /* Find the physical address of the v86 stack (ebx). */
+ movzwl TR_SS(%esp),%ebx
+ shll $4,%ebx
+ addl TR_ESP(%esp),%ebx
+
+ /* Store the return information into the v86 stack frame. */
+ movl TR_EIP(%esp),%eax
+ movw %ax,(%ebx)
+ movl TR_CS(%esp),%eax
+ movw %ax,2(%ebx)
+ movl TR_EFLAGS(%esp),%eax
+ movw %ax,4(%ebx)
+
+ /* Find the real-mode interrupt vector to invoke,
+ and set up the real_call_thread's kernel stack frame
+ to point to it. */
+ movl (%esi),%eax
+ movw %ax,TR_EIP(%esp)
+ shrl $16,%eax
+ movw %ax,TR_CS(%esp)
+ andl $-1-EFL_IF-EFL_TF,TR_EFLAGS(%esp)
+
+ /* Restore saved state and return. */
+ addl $4*4,%esp
+ popa
+ addl $4*2,%esp
+ iret
+
+
+
+/* We intercepted a copy-extended-memory software interrupt
+ (int 0x15 function 0x87).
+ This is used by HIMEM.SYS, for example, to manage extended memory.
+ The BIOS's routine isn't going to work in v86 mode,
+ so do it ourselves. */
+copy_ext_mem:
+
+ /* Find the parameter block provided by the caller (ebx). */
+ movzwl TR_V86_ES(%esp),%ebx
+ movzwl TR_ESI(%esp),%eax
+ shll $4,%ebx
+ addl %eax,%ebx
+
+ /* Source address (esi). */
+ movl 0x12(%ebx),%esi
+ andl $0x00ffffff,%esi
+
+ /* Destination address (edi). */
+ movl 0x1a(%ebx),%edi
+ andl $0x00ffffff,%edi
+
+ /* Number of bytes (ecx). */
+ movzwl TR_ECX(%esp),%ecx
+ addl %ecx,%ecx
+
+ /* Use the standard i386 bcopy routine to copy the data.
+ This assumes it's "friendly" in its use of segment registers
+ (i.e. always uses ss for stack data and ds/es for the data to copy).
+ The bcopy is simple enough that this should always be true. */
+ movw %ds,%ax
+ movw %ax,%es
+ cld
+ pushl %ecx
+ pushl %edi
+ pushl %esi
+ call EXT(bcopy)
+ addl $3*4,%esp
+
+ /* Clear the carry flag to indicate that the copy was successful.
+ AH is also cleared, below. */
+ andl $-1-EFL_CF,TR_EFLAGS(%esp)
+
+ /* Restore saved state and return. */
+ addl $4*4,%esp
+ popa
+ xorb %ah,%ah
+ addl $4*2,%esp
+ iret
+
diff --git a/i386/pc/rv86/trap_handler.S b/i386/pc/rv86/trap_handler.S
new file mode 100644
index 0000000..99254ee
--- /dev/null
+++ b/i386/pc/rv86/trap_handler.S
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1995-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 <mach/machine/asm.h>
+#include <mach/machine/eflags.h>
+
+#include "trap.h"
+#include "trap_asm.h"
+
+ .text
+
+ENTRY(trap_handler)
+
+ /* See if we came from v86 mode. */
+ testl $EFL_VM,TR_EFLAGS(%esp)
+ jnz EXT(rv86_trap_handler)
+
+ UNEXPECTED_TRAP
+