diff options
author | Thomas Bushnell <thomas@gnu.org> | 1997-02-25 21:28:37 +0000 |
---|---|---|
committer | Thomas Bushnell <thomas@gnu.org> | 1997-02-25 21:28:37 +0000 |
commit | f07a4c844da9f0ecae5bbee1ab94be56505f26f7 (patch) | |
tree | 12b07c7e578fc1a5f53dbfde2632408491ff2a70 /i386/pc/rv86 |
Initial source
Diffstat (limited to 'i386/pc/rv86')
-rw-r--r-- | i386/pc/rv86/config.h | 29 | ||||
-rw-r--r-- | i386/pc/rv86/gdt_sels.h | 60 | ||||
-rw-r--r-- | i386/pc/rv86/idt_irq_init.c | 40 | ||||
-rw-r--r-- | i386/pc/rv86/rv86_real_int.c | 276 | ||||
-rw-r--r-- | i386/pc/rv86/rv86_real_int_asm.S | 119 | ||||
-rw-r--r-- | i386/pc/rv86/rv86_reflect_irq.S | 113 | ||||
-rw-r--r-- | i386/pc/rv86/rv86_trap_handler.S | 167 | ||||
-rw-r--r-- | i386/pc/rv86/trap_handler.S | 39 |
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 + |