summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/exception.S14
-rw-r--r--sys/amd64/amd64/exception.s14
-rw-r--r--sys/amd64/amd64/locore.S53
-rw-r--r--sys/amd64/amd64/locore.s53
-rw-r--r--sys/amd64/amd64/machdep.c65
-rw-r--r--sys/amd64/amd64/sys_machdep.c5
-rw-r--r--sys/amd64/amd64/trap.c34
-rw-r--r--sys/amd64/amd64/vm_machdep.c10
-rw-r--r--sys/i386/i386/exception.s14
-rw-r--r--sys/i386/i386/locore.s53
-rw-r--r--sys/i386/i386/machdep.c65
-rw-r--r--sys/i386/i386/sys_machdep.c5
-rw-r--r--sys/i386/i386/trap.c34
-rw-r--r--sys/i386/i386/vm86.c323
-rw-r--r--sys/i386/i386/vm86bios.s209
-rw-r--r--sys/i386/i386/vm_machdep.c10
-rw-r--r--sys/i386/include/vm86.h95
-rw-r--r--sys/i386/isa/ipl.s9
-rw-r--r--sys/kern/subr_trap.c34
19 files changed, 986 insertions, 113 deletions
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S
index 596f4db..0b16ebe 100644
--- a/sys/amd64/amd64/exception.S
+++ b/sys/amd64/amd64/exception.S
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: exception.s,v 1.46 1997/10/27 16:35:34 bde Exp $
+ * $Id: exception.s,v 1.47 1997/10/27 17:19:20 bde Exp $
*/
#include "npx.h"
@@ -224,6 +224,10 @@ calltrap:
#ifndef SMP
subl %eax,%eax
#endif
+#ifdef VM86
+ cmpl $1,_in_vm86call
+ je 2f /* keep kernel cpl */
+#endif
testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
jne 1f
#ifdef VM86
@@ -231,6 +235,7 @@ calltrap:
jne 1f
#endif /* VM86 */
+2:
#ifdef SMP
ECPL_LOCK
#ifdef CPL_AND_CML
@@ -362,6 +367,13 @@ ENTRY(fork_trampoline)
jmp _doreti
+#ifdef VM86
+/*
+ * Include vm86 call routines, which want to call _doreti.
+ */
+#include "i386/i386/vm86bios.s"
+#endif /* VM86 */
+
/*
* Include what was once config+isa-dependent code.
* XXX it should be in a stand-alone file. It's still icu-dependent and
diff --git a/sys/amd64/amd64/exception.s b/sys/amd64/amd64/exception.s
index 596f4db..0b16ebe 100644
--- a/sys/amd64/amd64/exception.s
+++ b/sys/amd64/amd64/exception.s
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: exception.s,v 1.46 1997/10/27 16:35:34 bde Exp $
+ * $Id: exception.s,v 1.47 1997/10/27 17:19:20 bde Exp $
*/
#include "npx.h"
@@ -224,6 +224,10 @@ calltrap:
#ifndef SMP
subl %eax,%eax
#endif
+#ifdef VM86
+ cmpl $1,_in_vm86call
+ je 2f /* keep kernel cpl */
+#endif
testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
jne 1f
#ifdef VM86
@@ -231,6 +235,7 @@ calltrap:
jne 1f
#endif /* VM86 */
+2:
#ifdef SMP
ECPL_LOCK
#ifdef CPL_AND_CML
@@ -362,6 +367,13 @@ ENTRY(fork_trampoline)
jmp _doreti
+#ifdef VM86
+/*
+ * Include vm86 call routines, which want to call _doreti.
+ */
+#include "i386/i386/vm86bios.s"
+#endif /* VM86 */
+
/*
* Include what was once config+isa-dependent code.
* XXX it should be in a stand-alone file. It's still icu-dependent and
diff --git a/sys/amd64/amd64/locore.S b/sys/amd64/amd64/locore.S
index e5db5cc..a7f0436 100644
--- a/sys/amd64/amd64/locore.S
+++ b/sys/amd64/amd64/locore.S
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)locore.s 7.3 (Berkeley) 5/13/91
- * $Id: locore.s,v 1.103 1998/01/09 03:20:58 eivind Exp $
+ * $Id: locore.s,v 1.104 1998/01/31 02:53:41 eivind Exp $
*
* originally from: locore.s, by William F. Jolitz
*
@@ -185,6 +185,12 @@ _KPTphys: .long 0 /* phys addr of kernel page tables */
_proc0paddr: .long 0 /* address of proc 0 address space */
p0upa: .long 0 /* phys addr of proc0's UPAGES */
+#ifdef VM86
+ .globl _vm86paddr, _vm86pa
+_vm86paddr: .long 0 /* address of vm86 region */
+_vm86pa: .long 0 /* phys addr of vm86 region */
+#endif
+
#ifdef BDE_DEBUGGER
.globl _bdb_exists /* flag to indicate BDE debugger is present */
_bdb_exists: .long 0
@@ -828,6 +834,13 @@ over_symalloc:
addl $KERNBASE, %esi
movl %esi, R(_proc0paddr)
+#ifdef VM86
+ ALLOCPAGES(4) /* IOPAGES + ext + stack */
+ movl %esi,R(_vm86pa)
+ addl $KERNBASE, %esi
+ movl %esi, R(_vm86paddr)
+#endif /* VM86 */
+
#ifdef SMP
/* Allocate cpu0's private data page */
ALLOCPAGES(1)
@@ -894,6 +907,25 @@ map_read_write:
movl $ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx
fillkptphys($PG_RW)
+#ifdef VM86
+/* Map space for the vm86 region */
+ movl R(_vm86pa), %eax
+ movl $4, %ecx
+ fillkptphys($PG_RW)
+
+/* Map page 0 into the vm86 page table */
+ movl $0, %eax
+ movl $0, %ebx
+ movl $1, %ecx
+ fillkpt(R(_vm86pa), $PG_RW|PG_U)
+
+/* ...likewise for the ISA hole */
+ movl $ISA_HOLE_START, %eax
+ movl $ISA_HOLE_START>>PAGE_SHIFT, %ebx
+ movl $ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx
+ fillkpt(R(_vm86pa), $PG_RW|PG_U)
+#endif /* VM86 */
+
#ifdef SMP
/* Map cpu0's private page into global kmem (4K @ cpu0prvpage) */
movl R(cpu0pp), %eax
@@ -922,6 +954,25 @@ map_read_write:
movl $MPPTDI, %ebx
movl $1, %ecx
fillkpt(R(_IdlePTD), $PG_RW)
+
+/* Fakeup VA for the local apic to allow early traps. */
+ ALLOCPAGES(1)
+ movl %esi, %eax
+ movl $2, %ebx /* pte offset = 2 */
+ movl $1, %ecx /* one private pt coming right up */
+ fillkpt(R(cpu0pt), $PG_RW)
+
+/* Initialize mp lock to allow early traps */
+ movl $1, R(_mp_lock)
+
+/* Initialize curproc to &proc0 */
+ movl R(cpu0pp), %eax
+ movl $CNAME(proc0), 4(%eax)
+
+/* Initialize my_idlePTD to IdlePTD */
+ movl R(_IdlePTD), %ecx
+ movl %ecx,32(%eax)
+
#endif /* SMP */
/* install a pde for temporary double map of bottom of VA */
diff --git a/sys/amd64/amd64/locore.s b/sys/amd64/amd64/locore.s
index e5db5cc..a7f0436 100644
--- a/sys/amd64/amd64/locore.s
+++ b/sys/amd64/amd64/locore.s
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)locore.s 7.3 (Berkeley) 5/13/91
- * $Id: locore.s,v 1.103 1998/01/09 03:20:58 eivind Exp $
+ * $Id: locore.s,v 1.104 1998/01/31 02:53:41 eivind Exp $
*
* originally from: locore.s, by William F. Jolitz
*
@@ -185,6 +185,12 @@ _KPTphys: .long 0 /* phys addr of kernel page tables */
_proc0paddr: .long 0 /* address of proc 0 address space */
p0upa: .long 0 /* phys addr of proc0's UPAGES */
+#ifdef VM86
+ .globl _vm86paddr, _vm86pa
+_vm86paddr: .long 0 /* address of vm86 region */
+_vm86pa: .long 0 /* phys addr of vm86 region */
+#endif
+
#ifdef BDE_DEBUGGER
.globl _bdb_exists /* flag to indicate BDE debugger is present */
_bdb_exists: .long 0
@@ -828,6 +834,13 @@ over_symalloc:
addl $KERNBASE, %esi
movl %esi, R(_proc0paddr)
+#ifdef VM86
+ ALLOCPAGES(4) /* IOPAGES + ext + stack */
+ movl %esi,R(_vm86pa)
+ addl $KERNBASE, %esi
+ movl %esi, R(_vm86paddr)
+#endif /* VM86 */
+
#ifdef SMP
/* Allocate cpu0's private data page */
ALLOCPAGES(1)
@@ -894,6 +907,25 @@ map_read_write:
movl $ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx
fillkptphys($PG_RW)
+#ifdef VM86
+/* Map space for the vm86 region */
+ movl R(_vm86pa), %eax
+ movl $4, %ecx
+ fillkptphys($PG_RW)
+
+/* Map page 0 into the vm86 page table */
+ movl $0, %eax
+ movl $0, %ebx
+ movl $1, %ecx
+ fillkpt(R(_vm86pa), $PG_RW|PG_U)
+
+/* ...likewise for the ISA hole */
+ movl $ISA_HOLE_START, %eax
+ movl $ISA_HOLE_START>>PAGE_SHIFT, %ebx
+ movl $ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx
+ fillkpt(R(_vm86pa), $PG_RW|PG_U)
+#endif /* VM86 */
+
#ifdef SMP
/* Map cpu0's private page into global kmem (4K @ cpu0prvpage) */
movl R(cpu0pp), %eax
@@ -922,6 +954,25 @@ map_read_write:
movl $MPPTDI, %ebx
movl $1, %ecx
fillkpt(R(_IdlePTD), $PG_RW)
+
+/* Fakeup VA for the local apic to allow early traps. */
+ ALLOCPAGES(1)
+ movl %esi, %eax
+ movl $2, %ebx /* pte offset = 2 */
+ movl $1, %ecx /* one private pt coming right up */
+ fillkpt(R(cpu0pt), $PG_RW)
+
+/* Initialize mp lock to allow early traps */
+ movl $1, R(_mp_lock)
+
+/* Initialize curproc to &proc0 */
+ movl R(cpu0pp), %eax
+ movl $CNAME(proc0), 4(%eax)
+
+/* Initialize my_idlePTD to IdlePTD */
+ movl R(_IdlePTD), %ecx
+ movl %ecx,32(%eax)
+
#endif /* SMP */
/* install a pde for temporary double map of bottom of VA */
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 14f0edc..1ecb116 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
- * $Id: machdep.c,v 1.291 1998/03/05 19:37:03 tegge Exp $
+ * $Id: machdep.c,v 1.292 1998/03/07 20:16:47 tegge Exp $
*/
#include "apm.h"
@@ -645,8 +645,6 @@ sigreturn(p, uap)
if ((eflags & PSL_VIP) && (eflags & PSL_VIF))
trapsignal(p, SIGBUS, 0);
-#define VM_USERCHANGE (PSL_USERCHANGE | PSL_RF)
-#define VME_USERCHANGE (VM_USERCHANGE | PSL_VIP | PSL_VIF)
if (vm86->vm86_has_vme) {
eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
(eflags & VME_USERCHANGE) | PSL_VM;
@@ -1239,11 +1237,43 @@ init386(first)
setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
initializecpu(); /* Initialize CPU registers */
+ /* make an initial tss so cpu can get interrupt stack on syscall! */
+#ifdef VM86
+ common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE - 16;
+#else
+ common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE;
+#endif /* VM86 */
+ common_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
+ common_tss.tss_ioopt = (sizeof common_tss) << 16;
+ gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
+ ltr(gsel_tss);
+#ifdef VM86
+ private_tss = 0;
+ my_tr = GPROC0_SEL;
+#endif
+
+ dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 =
+ dblfault_tss.tss_esp2 = (int) &dblfault_stack[sizeof(dblfault_stack)];
+ dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 =
+ dblfault_tss.tss_ss2 = GSEL(GDATA_SEL, SEL_KPL);
+ dblfault_tss.tss_cr3 = (int)IdlePTD;
+ dblfault_tss.tss_eip = (int) dblfault_handler;
+ dblfault_tss.tss_eflags = PSL_KERNEL;
+ dblfault_tss.tss_ds = dblfault_tss.tss_es = dblfault_tss.tss_fs =
+ dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL);
+ dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL);
+ dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL);
+
+#ifdef VM86
+ initial_bioscalls(&biosbasemem, &biosextmem);
+#else
+
/* Use BIOS values stored in RTC CMOS RAM, since probing
* breaks certain 386 AT relics.
*/
biosbasemem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8);
biosextmem = rtcin(RTC_EXTLO)+ (rtcin(RTC_EXTHI)<<8);
+#endif
/*
* If BIOS tells us that it has more than 640k in the basemem,
@@ -1290,7 +1320,7 @@ init386(first)
* remain read-only and are unused by the kernel.
* The base memory area is below the physical end of
* the kernel and right now forms a read-only hole.
- * The part of it from 0 to
+ * The part of it from PAGE_SIZE to
* (trunc_page(biosbasemem * 1024) - 1) will be
* remapped and used by the kernel later.)
*
@@ -1505,33 +1535,6 @@ init386(first)
avail_end + off, VM_PROT_ALL, TRUE);
msgbufmapped = 1;
- /* make an initial tss so cpu can get interrupt stack on syscall! */
-#ifdef VM86
- common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE - 16;
-#else
- common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE;
-#endif /* VM86 */
- common_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
- common_tss.tss_ioopt = (sizeof common_tss) << 16;
- gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
- ltr(gsel_tss);
-#ifdef VM86
- private_tss = 0;
- my_tr = GPROC0_SEL;
-#endif
-
- dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 =
- dblfault_tss.tss_esp2 = (int) &dblfault_stack[sizeof(dblfault_stack)];
- dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 =
- dblfault_tss.tss_ss2 = GSEL(GDATA_SEL, SEL_KPL);
- dblfault_tss.tss_cr3 = (int)IdlePTD;
- dblfault_tss.tss_eip = (int) dblfault_handler;
- dblfault_tss.tss_eflags = PSL_KERNEL;
- dblfault_tss.tss_ds = dblfault_tss.tss_es = dblfault_tss.tss_fs =
- dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL);
- dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL);
- dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL);
-
/* make a call gate to reenter kernel with */
gdp = &ldt[LSYS5CALLS_SEL].gd;
diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c
index aed0483..af0ec8e 100644
--- a/sys/amd64/amd64/sys_machdep.c
+++ b/sys/amd64/amd64/sys_machdep.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)sys_machdep.c 5.5 (Berkeley) 1/19/91
- * $Id: sys_machdep.c,v 1.32 1998/02/09 06:08:18 eivind Exp $
+ * $Id: sys_machdep.c,v 1.33 1998/02/13 05:25:37 bde Exp $
*
*/
@@ -140,7 +140,7 @@ i386_extend_pcb(struct proc *p)
if (ext == 0)
return (ENOMEM);
p->p_addr->u_pcb.pcb_ext = ext;
- bzero(&ext->ext_tss, sizeof(struct i386tss));
+ bzero(ext, sizeof(struct pcb_ext));
ext->ext_tss.tss_esp0 = (unsigned)p->p_addr + ctob(UPAGES) - 16;
ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
/*
@@ -153,7 +153,6 @@ i386_extend_pcb(struct proc *p)
(offset - ((unsigned)&ext->ext_tss - (unsigned)ext)) << 16;
ext->ext_iomap = (caddr_t)ext + offset;
ext->ext_vm86.vm86_intmap = (caddr_t)ext + offset - 32;
- ext->ext_vm86.vm86_inited = 0;
addr = (u_long *)ext->ext_vm86.vm86_intmap;
for (i = 0; i < (ctob(IOPAGES) + 32 + 16) / sizeof(u_long); i++)
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index 79715f5..5e1bb32 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)trap.c 7.4 (Berkeley) 5/13/91
- * $Id: trap.c,v 1.121 1998/02/04 22:32:12 eivind Exp $
+ * $Id: trap.c,v 1.122 1998/02/06 12:13:10 eivind Exp $
*/
/*
@@ -225,6 +225,35 @@ restart:
type = frame.tf_trapno;
code = frame.tf_err;
+#ifdef VM86
+ if (in_vm86call) {
+ if (frame.tf_eflags & PSL_VM &&
+ (type == T_PROTFLT || type == T_STKFLT)) {
+ i = vm86_emulate((struct vm86frame *)&frame);
+ if (i != 0)
+ /*
+ * returns to original process
+ */
+ vm86_trap((struct vm86frame *)&frame);
+ return;
+ }
+ switch (type) {
+ /*
+ * these traps want either a process context, or
+ * assume a normal userspace trap.
+ */
+ case T_PROTFLT:
+ case T_SEGNPFLT:
+ trap_fatal(&frame);
+ return;
+ case T_TRCTRAP:
+ type = T_BPTFLT; /* kernel breakpoint */
+ /* FALL THROUGH */
+ }
+ goto kernel_trap; /* normal kernel trap handling */
+ }
+#endif
+
if ((ISPL(frame.tf_cs) == SEL_UPL) || (frame.tf_eflags & PSL_VM)) {
/* user trap */
@@ -356,6 +385,9 @@ restart:
break;
}
} else {
+#ifdef VM86
+kernel_trap:
+#endif
/* kernel trap */
switch (type) {
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
index 8ac19b1..b157bb6 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -38,7 +38,7 @@
*
* from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91
* Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
- * $Id: vm_machdep.c,v 1.103 1998/03/14 03:02:15 tegge Exp $
+ * $Id: vm_machdep.c,v 1.104 1998/03/17 09:10:05 kato Exp $
*/
#include "npx.h"
@@ -65,6 +65,10 @@
#ifdef SMP
#include <machine/smp.h>
#endif
+#ifdef VM86
+#include <machine/pcb_ext.h>
+#include <machine/vm86.h>
+#endif
#include <vm/vm.h>
#include <vm/vm_param.h>
@@ -599,7 +603,11 @@ cpu_fork(p1, p2)
* syscall. This copies the user mode register values.
*/
p2->p_md.md_regs = (struct trapframe *)
+#ifdef VM86
+ ((int)p2->p_addr + UPAGES * PAGE_SIZE - 16) - 1;
+#else
((int)p2->p_addr + UPAGES * PAGE_SIZE) - 1;
+#endif /* VM86 */
*p2->p_md.md_regs = *p1->p_md.md_regs;
/*
diff --git a/sys/i386/i386/exception.s b/sys/i386/i386/exception.s
index 596f4db..0b16ebe 100644
--- a/sys/i386/i386/exception.s
+++ b/sys/i386/i386/exception.s
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: exception.s,v 1.46 1997/10/27 16:35:34 bde Exp $
+ * $Id: exception.s,v 1.47 1997/10/27 17:19:20 bde Exp $
*/
#include "npx.h"
@@ -224,6 +224,10 @@ calltrap:
#ifndef SMP
subl %eax,%eax
#endif
+#ifdef VM86
+ cmpl $1,_in_vm86call
+ je 2f /* keep kernel cpl */
+#endif
testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
jne 1f
#ifdef VM86
@@ -231,6 +235,7 @@ calltrap:
jne 1f
#endif /* VM86 */
+2:
#ifdef SMP
ECPL_LOCK
#ifdef CPL_AND_CML
@@ -362,6 +367,13 @@ ENTRY(fork_trampoline)
jmp _doreti
+#ifdef VM86
+/*
+ * Include vm86 call routines, which want to call _doreti.
+ */
+#include "i386/i386/vm86bios.s"
+#endif /* VM86 */
+
/*
* Include what was once config+isa-dependent code.
* XXX it should be in a stand-alone file. It's still icu-dependent and
diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s
index e5db5cc..a7f0436 100644
--- a/sys/i386/i386/locore.s
+++ b/sys/i386/i386/locore.s
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)locore.s 7.3 (Berkeley) 5/13/91
- * $Id: locore.s,v 1.103 1998/01/09 03:20:58 eivind Exp $
+ * $Id: locore.s,v 1.104 1998/01/31 02:53:41 eivind Exp $
*
* originally from: locore.s, by William F. Jolitz
*
@@ -185,6 +185,12 @@ _KPTphys: .long 0 /* phys addr of kernel page tables */
_proc0paddr: .long 0 /* address of proc 0 address space */
p0upa: .long 0 /* phys addr of proc0's UPAGES */
+#ifdef VM86
+ .globl _vm86paddr, _vm86pa
+_vm86paddr: .long 0 /* address of vm86 region */
+_vm86pa: .long 0 /* phys addr of vm86 region */
+#endif
+
#ifdef BDE_DEBUGGER
.globl _bdb_exists /* flag to indicate BDE debugger is present */
_bdb_exists: .long 0
@@ -828,6 +834,13 @@ over_symalloc:
addl $KERNBASE, %esi
movl %esi, R(_proc0paddr)
+#ifdef VM86
+ ALLOCPAGES(4) /* IOPAGES + ext + stack */
+ movl %esi,R(_vm86pa)
+ addl $KERNBASE, %esi
+ movl %esi, R(_vm86paddr)
+#endif /* VM86 */
+
#ifdef SMP
/* Allocate cpu0's private data page */
ALLOCPAGES(1)
@@ -894,6 +907,25 @@ map_read_write:
movl $ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx
fillkptphys($PG_RW)
+#ifdef VM86
+/* Map space for the vm86 region */
+ movl R(_vm86pa), %eax
+ movl $4, %ecx
+ fillkptphys($PG_RW)
+
+/* Map page 0 into the vm86 page table */
+ movl $0, %eax
+ movl $0, %ebx
+ movl $1, %ecx
+ fillkpt(R(_vm86pa), $PG_RW|PG_U)
+
+/* ...likewise for the ISA hole */
+ movl $ISA_HOLE_START, %eax
+ movl $ISA_HOLE_START>>PAGE_SHIFT, %ebx
+ movl $ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx
+ fillkpt(R(_vm86pa), $PG_RW|PG_U)
+#endif /* VM86 */
+
#ifdef SMP
/* Map cpu0's private page into global kmem (4K @ cpu0prvpage) */
movl R(cpu0pp), %eax
@@ -922,6 +954,25 @@ map_read_write:
movl $MPPTDI, %ebx
movl $1, %ecx
fillkpt(R(_IdlePTD), $PG_RW)
+
+/* Fakeup VA for the local apic to allow early traps. */
+ ALLOCPAGES(1)
+ movl %esi, %eax
+ movl $2, %ebx /* pte offset = 2 */
+ movl $1, %ecx /* one private pt coming right up */
+ fillkpt(R(cpu0pt), $PG_RW)
+
+/* Initialize mp lock to allow early traps */
+ movl $1, R(_mp_lock)
+
+/* Initialize curproc to &proc0 */
+ movl R(cpu0pp), %eax
+ movl $CNAME(proc0), 4(%eax)
+
+/* Initialize my_idlePTD to IdlePTD */
+ movl R(_IdlePTD), %ecx
+ movl %ecx,32(%eax)
+
#endif /* SMP */
/* install a pde for temporary double map of bottom of VA */
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 14f0edc..1ecb116 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
- * $Id: machdep.c,v 1.291 1998/03/05 19:37:03 tegge Exp $
+ * $Id: machdep.c,v 1.292 1998/03/07 20:16:47 tegge Exp $
*/
#include "apm.h"
@@ -645,8 +645,6 @@ sigreturn(p, uap)
if ((eflags & PSL_VIP) && (eflags & PSL_VIF))
trapsignal(p, SIGBUS, 0);
-#define VM_USERCHANGE (PSL_USERCHANGE | PSL_RF)
-#define VME_USERCHANGE (VM_USERCHANGE | PSL_VIP | PSL_VIF)
if (vm86->vm86_has_vme) {
eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
(eflags & VME_USERCHANGE) | PSL_VM;
@@ -1239,11 +1237,43 @@ init386(first)
setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
initializecpu(); /* Initialize CPU registers */
+ /* make an initial tss so cpu can get interrupt stack on syscall! */
+#ifdef VM86
+ common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE - 16;
+#else
+ common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE;
+#endif /* VM86 */
+ common_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
+ common_tss.tss_ioopt = (sizeof common_tss) << 16;
+ gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
+ ltr(gsel_tss);
+#ifdef VM86
+ private_tss = 0;
+ my_tr = GPROC0_SEL;
+#endif
+
+ dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 =
+ dblfault_tss.tss_esp2 = (int) &dblfault_stack[sizeof(dblfault_stack)];
+ dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 =
+ dblfault_tss.tss_ss2 = GSEL(GDATA_SEL, SEL_KPL);
+ dblfault_tss.tss_cr3 = (int)IdlePTD;
+ dblfault_tss.tss_eip = (int) dblfault_handler;
+ dblfault_tss.tss_eflags = PSL_KERNEL;
+ dblfault_tss.tss_ds = dblfault_tss.tss_es = dblfault_tss.tss_fs =
+ dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL);
+ dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL);
+ dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL);
+
+#ifdef VM86
+ initial_bioscalls(&biosbasemem, &biosextmem);
+#else
+
/* Use BIOS values stored in RTC CMOS RAM, since probing
* breaks certain 386 AT relics.
*/
biosbasemem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8);
biosextmem = rtcin(RTC_EXTLO)+ (rtcin(RTC_EXTHI)<<8);
+#endif
/*
* If BIOS tells us that it has more than 640k in the basemem,
@@ -1290,7 +1320,7 @@ init386(first)
* remain read-only and are unused by the kernel.
* The base memory area is below the physical end of
* the kernel and right now forms a read-only hole.
- * The part of it from 0 to
+ * The part of it from PAGE_SIZE to
* (trunc_page(biosbasemem * 1024) - 1) will be
* remapped and used by the kernel later.)
*
@@ -1505,33 +1535,6 @@ init386(first)
avail_end + off, VM_PROT_ALL, TRUE);
msgbufmapped = 1;
- /* make an initial tss so cpu can get interrupt stack on syscall! */
-#ifdef VM86
- common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE - 16;
-#else
- common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE;
-#endif /* VM86 */
- common_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
- common_tss.tss_ioopt = (sizeof common_tss) << 16;
- gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
- ltr(gsel_tss);
-#ifdef VM86
- private_tss = 0;
- my_tr = GPROC0_SEL;
-#endif
-
- dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 =
- dblfault_tss.tss_esp2 = (int) &dblfault_stack[sizeof(dblfault_stack)];
- dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 =
- dblfault_tss.tss_ss2 = GSEL(GDATA_SEL, SEL_KPL);
- dblfault_tss.tss_cr3 = (int)IdlePTD;
- dblfault_tss.tss_eip = (int) dblfault_handler;
- dblfault_tss.tss_eflags = PSL_KERNEL;
- dblfault_tss.tss_ds = dblfault_tss.tss_es = dblfault_tss.tss_fs =
- dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL);
- dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL);
- dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL);
-
/* make a call gate to reenter kernel with */
gdp = &ldt[LSYS5CALLS_SEL].gd;
diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c
index aed0483..af0ec8e 100644
--- a/sys/i386/i386/sys_machdep.c
+++ b/sys/i386/i386/sys_machdep.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)sys_machdep.c 5.5 (Berkeley) 1/19/91
- * $Id: sys_machdep.c,v 1.32 1998/02/09 06:08:18 eivind Exp $
+ * $Id: sys_machdep.c,v 1.33 1998/02/13 05:25:37 bde Exp $
*
*/
@@ -140,7 +140,7 @@ i386_extend_pcb(struct proc *p)
if (ext == 0)
return (ENOMEM);
p->p_addr->u_pcb.pcb_ext = ext;
- bzero(&ext->ext_tss, sizeof(struct i386tss));
+ bzero(ext, sizeof(struct pcb_ext));
ext->ext_tss.tss_esp0 = (unsigned)p->p_addr + ctob(UPAGES) - 16;
ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
/*
@@ -153,7 +153,6 @@ i386_extend_pcb(struct proc *p)
(offset - ((unsigned)&ext->ext_tss - (unsigned)ext)) << 16;
ext->ext_iomap = (caddr_t)ext + offset;
ext->ext_vm86.vm86_intmap = (caddr_t)ext + offset - 32;
- ext->ext_vm86.vm86_inited = 0;
addr = (u_long *)ext->ext_vm86.vm86_intmap;
for (i = 0; i < (ctob(IOPAGES) + 32 + 16) / sizeof(u_long); i++)
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index 79715f5..5e1bb32 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)trap.c 7.4 (Berkeley) 5/13/91
- * $Id: trap.c,v 1.121 1998/02/04 22:32:12 eivind Exp $
+ * $Id: trap.c,v 1.122 1998/02/06 12:13:10 eivind Exp $
*/
/*
@@ -225,6 +225,35 @@ restart:
type = frame.tf_trapno;
code = frame.tf_err;
+#ifdef VM86
+ if (in_vm86call) {
+ if (frame.tf_eflags & PSL_VM &&
+ (type == T_PROTFLT || type == T_STKFLT)) {
+ i = vm86_emulate((struct vm86frame *)&frame);
+ if (i != 0)
+ /*
+ * returns to original process
+ */
+ vm86_trap((struct vm86frame *)&frame);
+ return;
+ }
+ switch (type) {
+ /*
+ * these traps want either a process context, or
+ * assume a normal userspace trap.
+ */
+ case T_PROTFLT:
+ case T_SEGNPFLT:
+ trap_fatal(&frame);
+ return;
+ case T_TRCTRAP:
+ type = T_BPTFLT; /* kernel breakpoint */
+ /* FALL THROUGH */
+ }
+ goto kernel_trap; /* normal kernel trap handling */
+ }
+#endif
+
if ((ISPL(frame.tf_cs) == SEL_UPL) || (frame.tf_eflags & PSL_VM)) {
/* user trap */
@@ -356,6 +385,9 @@ restart:
break;
}
} else {
+#ifdef VM86
+kernel_trap:
+#endif
/* kernel trap */
switch (type) {
diff --git a/sys/i386/i386/vm86.c b/sys/i386/i386/vm86.c
index c3e463c..599d8ac 100644
--- a/sys/i386/i386/vm86.c
+++ b/sys/i386/i386/vm86.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: vm86.c,v 1.7 1998/02/04 22:32:12 eivind Exp $
+ * $Id: vm86.c,v 1.8 1998/02/06 12:13:11 eivind Exp $
*/
#include "opt_vm86.h"
@@ -38,6 +38,7 @@
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <vm/vm_page.h>
+#include <vm/vm_param.h>
#include <sys/user.h>
@@ -47,13 +48,23 @@
#include <machine/specialreg.h>
extern int i386_extend_pcb __P((struct proc *));
+extern struct segment_descriptor common_tssd;
+extern int vm86paddr, vm86pa;
+extern struct pcb *vm86pcb;
+extern int vm86_bioscall(struct vm86frame *);
+extern void vm86_biosret(struct vm86frame *);
+
+void vm86_prepcall(struct vm86frame);
+
+#define HLT 0xf4
#define CLI 0xfa
#define STI 0xfb
#define PUSHF 0x9c
#define POPF 0x9d
#define INTn 0xcd
#define IRET 0xcf
+#define CALLm 0xff
#define OPERAND_SIZE_PREFIX 0x66
#define ADDRESS_SIZE_PREFIX 0x67
#define PUSH_MASK ~(PSL_VM | PSL_RF | PSL_I)
@@ -323,6 +334,303 @@ vm86_emulate(vmf)
return (SIGBUS);
}
+static void
+vm86_initialize(void)
+{
+ int i, offset;
+ u_long *addr;
+ struct pcb *pcb;
+ struct pcb_ext *ext;
+ struct segment_descriptor sd;
+ struct soft_segment_descriptor ssd = {
+ 0, /* segment base address (overwritten) */
+ ctob(IOPAGES + 1) - 1, /* length */
+ SDT_SYS386TSS, /* segment type */
+ 0, /* priority level */
+ 1, /* descriptor present */
+ 0, 0,
+ 0, /* default 32 size */
+ 0 /* granularity */
+ };
+
+ /*
+ * Below is the memory layout that we use for the vm86 region.
+ *
+ * The last byte of the i/o map must be followed by an 0xff byte.
+ * We arbitrarily allocate 16 bytes here, to keep the starting
+ * address on a doubleword boundary.
+ *
+ * If a ~2K stack is enough for interrupt handling, then
+ * it may be possible to get the page count down to 3 pages.
+ *
+ * +--------+ +--------+
+ * | | |Page Tbl| 1M + 64K = 272 entries = 1088 bytes
+ * | | +--------+
+ * | page 0 |
+ * | | +--------+
+ * | | | stack |
+ * +--------+ +--------+
+ * +--------+ +--------+
+ * | | | PCB | size: ~240 bytes
+ * | | |PCB Ext | size: ~140 bytes (includes TSS)
+ * | | +--------+
+ * | page 1 |
+ * | | +--------+
+ * | | |int map |
+ * | | +--------+ <-- &(PAGE 1) - 16
+ * +--------+ | |
+ * | page 2 | | I/O |
+ * +--------+ | bitmap |
+ * | page 3 | | |
+ * +--------+ +--------+
+ */
+
+ /*
+ * A rudimentary PCB must be installed, in order to get to the
+ * PCB extension area. We use the PCB area as a scratchpad for
+ * data storage, the layout of which is shown below.
+ *
+ * pcb_esi = new PTD entry 0
+ * pcb_ebp = pointer to frame on vm86 stack
+ * pcb_esp = stack frame pointer at time of switch
+ * pcb_ebx = va of vm86 page table
+ * pcb_eip = argument pointer to initial call
+ * pcb_fs = saved TSS descriptor, word 0
+ * pcb_gs = saved TSS descriptor, word 1
+ */
+
+ pcb = (struct pcb *)(vm86paddr + PAGE_SIZE);
+ bzero(pcb, sizeof(struct pcb));
+ pcb->pcb_esi = vm86pa | PG_V | PG_RW | PG_U;
+ pcb->pcb_ebp = vm86paddr + PAGE_SIZE - sizeof(struct vm86frame);
+ pcb->pcb_ebx = vm86paddr;
+
+ ext = (struct pcb_ext *)((u_int)pcb + sizeof(struct pcb));
+ pcb->pcb_ext = ext;
+
+ bzero(ext, sizeof(struct pcb_ext));
+ ext->ext_tss.tss_esp0 = vm86paddr + PAGE_SIZE;
+ ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
+
+ offset = PAGE_SIZE - 16;
+ ext->ext_tss.tss_ioopt =
+ (offset - ((u_int)&ext->ext_tss & PAGE_MASK)) << 16;
+ ext->ext_iomap = (caddr_t)(offset + ((u_int)&ext->ext_tss & PG_FRAME));
+
+ ext->ext_vm86.vm86_intmap = ext->ext_iomap - 32;
+ ext->ext_vm86.vm86_has_vme = (rcr4() & CR4_VME ? 1 : 0);
+
+ addr = (u_long *)ext->ext_vm86.vm86_intmap;
+ for (i = 0; i < (ctob(IOPAGES) + 32 + 16) / sizeof(u_long); i++)
+ *addr++ = 0;
+
+ ssd.ssd_base = (u_int)&ext->ext_tss;
+ ssd.ssd_limit -= ((u_int)&ext->ext_tss & PAGE_MASK);
+ ssdtosd(&ssd, &ext->ext_tssd);
+
+ vm86pcb = pcb;
+}
+
+void
+initial_bioscalls(u_int *basemem, u_int *extmem)
+{
+ int i, method;
+ struct vm86frame vmf;
+ u_int64_t highwat = 0;
+ struct {
+ u_int64_t base;
+ u_int64_t length;
+ u_int32_t type;
+ } smap;
+
+ bzero(&vmf, sizeof(struct vm86frame)); /* safety */
+ vm86_initialize();
+
+ vm86_intcall(0x12, &vmf);
+ *basemem = vmf.vmf_ax;
+ *extmem = 0;
+
+ /*
+ * if basemem != 640, map pages r/w into vm86 page table so
+ * that the bios can scribble on it.
+ */
+ for (i = *basemem / 4; i < 160; i++) {
+ u_int *pte = (u_int *)vm86paddr;
+ pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U;
+ }
+
+ /*
+ * get memory map with INT 15:E820
+ */
+#define SMAPSIZ sizeof(smap)
+#define SMAP_SIG 0x534D4150 /* 'SMAP' */
+ vmf.vmf_ebx = 0;
+ do {
+ vmf.vmf_eax = 0xE820;
+ vmf.vmf_edx = SMAP_SIG;
+ vmf.vmf_ecx = SMAPSIZ;
+ i = vm86_datacall(0x15, &vmf,
+ (char *)&smap, SMAPSIZ, &vmf.vmf_es, &vmf.vmf_di);
+ if (i || vmf.vmf_eax != SMAP_SIG)
+ break;
+ if (smap.type == 0x01 && smap.base >= highwat) {
+ *extmem += (smap.length / 1024);
+ highwat = smap.base + smap.length;
+ }
+ } while (vmf.vmf_ebx != 0);
+
+ if (*extmem != 0) {
+ if (*extmem > *basemem) {
+ *extmem -= *basemem;
+ method = 0xE820;
+ goto done;
+ }
+ printf("E820: extmem (%d) < basemem (%d)\n", *extmem, *basemem);
+ }
+
+ /*
+ * try memory map with INT 15:E801
+ */
+ vmf.vmf_ax = 0xE801;
+ if (vm86_intcall(0x15, &vmf) == 0) {
+ *extmem = vmf.vmf_cx + vmf.vmf_dx * 64;
+ method = 0xE801;
+ goto done;
+ }
+
+ vmf.vmf_ah = 0x88;
+ vm86_intcall(0x15, &vmf);
+ *extmem = vmf.vmf_ax;
+ method = 0x88;
+
+done:
+ printf("BIOS basemem: %dK, extmem: %dK (from %p call)\n",
+ *basemem, *extmem, method);
+
+#if 0
+ /* VESA setup -- ? */
+ vmf.vmf_ax = 0x4f02;
+ error = vm86_intcall(0x10, &vmf);
+#endif
+}
+
+static void
+vm86_initflags(struct vm86frame *vmf)
+{
+ int eflags = vmf->vmf_eflags;
+ struct vm86_kernel *vm86 = &curpcb->pcb_ext->ext_vm86;
+
+ if (vm86->vm86_has_vme) {
+ eflags = (vmf->vmf_eflags & ~VME_USERCHANGE) |
+ (eflags & VME_USERCHANGE) | PSL_VM;
+ } else {
+ vm86->vm86_eflags = eflags; /* save VIF, VIP */
+ eflags = (vmf->vmf_eflags & ~VM_USERCHANGE) |
+ (eflags & VM_USERCHANGE) | PSL_VM;
+ }
+ vmf->vmf_eflags = eflags | PSL_VM;
+}
+
+/*
+ * called from vm86_bioscall, while in vm86 address space, to finalize setup.
+ */
+void
+vm86_prepcall(struct vm86frame vmf)
+{
+ u_long addr[] = { 0xA00, 0x1000 }; /* code, stack */
+ u_char intcall[] = {
+ CLI, INTn, 0x00, STI, HLT
+ };
+
+ if ((vmf.vmf_trapno & PAGE_MASK) <= 0xff) {
+ /* interrupt call requested */
+ intcall[2] = (u_char)(vmf.vmf_trapno & 0xff);
+ memcpy((void *)addr[0], (void *)intcall, sizeof(intcall));
+ vmf.vmf_ip = addr[0];
+ vmf.vmf_cs = 0;
+ }
+ vmf.vmf_sp = addr[1] - 2; /* keep aligned */
+ vmf.kernel_es = vmf.kernel_ds = 0;
+ vmf.vmf_ss = 0;
+ vmf.vmf_eflags = PSL_VIF | PSL_VM | PSL_USER;
+ vm86_initflags(&vmf);
+}
+
+/*
+ * vm86 trap handler; determines whether routine succeeded or not.
+ * Called while in vm86 space, returns to calling process.
+ */
+void
+vm86_trap(struct vm86frame *vmf)
+{
+ caddr_t addr;
+
+ /* "should not happen" */
+ if ((vmf->vmf_eflags & PSL_VM) == 0)
+ panic("vm86_trap called, but not in vm86 mode");
+
+ addr = MAKE_ADDR(vmf->vmf_cs, vmf->vmf_ip);
+ if (*(u_char *)addr == HLT)
+ vmf->vmf_trapno = vmf->vmf_eflags & PSL_C;
+ else
+ vmf->vmf_trapno = vmf->vmf_trapno << 16;
+
+ vm86_biosret(vmf);
+}
+
+int
+vm86_intcall(int intnum, struct vm86frame *vmf)
+{
+ if (intnum < 0 || intnum > 0xff)
+ return (EINVAL);
+
+ vmf->vmf_trapno = intnum;
+ return (vm86_bioscall(vmf));
+}
+
+/*
+ * buffer must be entirely contained in a wired down page in kernel memory,
+ * and is mapped into page 1 in vm86 space. segment/offset will be filled
+ * in to create a vm86 pointer to the buffer. If intnum is a valid
+ * interrupt number (0-255), then the "interrupt trampoline" will be
+ * used, otherwise we use the caller's cs:ip routine.
+ *
+ * a future revision may allow multiple pages to be mapped, or allow
+ * the caller to pass in a custom page table to use.
+ */
+int
+vm86_datacall(intnum, vmf, buffer, buflen, segment, offset)
+ int intnum;
+ struct vm86frame *vmf;
+ char *buffer;
+ int buflen;
+ u_short *segment, *offset;
+{
+ u_int page;
+
+ page = (u_int)buffer & PG_FRAME;
+ *offset = (u_int)buffer & PAGE_MASK;
+ if ((*offset + buflen) & PG_FRAME)
+ return (-1); /* XXX fixme! */
+ *segment = 0x100;
+ page = vtophys(page);
+ vmf->vmf_trapno = page | (intnum & PAGE_MASK);
+ return (vm86_bioscall(vmf));
+}
+
+#if 0
+int
+vm86_datacall(int intnum, u_int kpage, struct vm86frame *vmf)
+{
+ if (kpage & PAGE_MASK)
+ return (EINVAL);
+ kpage = vtophys(kpage);
+
+ vmf->vmf_trapno = kpage | (intnum & PAGE_MASK);
+ return (vm86_bioscall(vmf));
+}
+#endif
+
int
vm86_sysarch(p, args)
struct proc *p;
@@ -381,6 +689,19 @@ vm86_sysarch(p, args)
}
break;
+#if 0
+ case VM86_INTCALL: {
+ struct vm86_intcall_args sa;
+
+ if (error = copyin(ua.sub_args, &sa, sizeof(sa)))
+ return (error);
+ if (error = vm86_intcall(sa.intnum, &sa.vmf))
+ return (error);
+ error = copyout(&sa, ua.sub_args, sizeof(sa));
+ }
+ break;
+#endif
+
default:
error = EINVAL;
}
diff --git a/sys/i386/i386/vm86bios.s b/sys/i386/i386/vm86bios.s
new file mode 100644
index 0000000..49e4dce
--- /dev/null
+++ b/sys/i386/i386/vm86bios.s
@@ -0,0 +1,209 @@
+/*-
+ * Copyright (c) 1998 Jonathan Lemon
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include "opt_vm86.h"
+
+#include <machine/asmacros.h> /* miscellaneous asm macros */
+#include <machine/trap.h>
+
+#include "assym.s"
+
+ .data
+ ALIGN_DATA
+
+ .globl _in_vm86call, _vm86pcb
+
+_in_vm86call: .long 0
+_vm86pcb: .long 0
+
+ .text
+
+/*
+ * vm86_bioscall(struct trapframe_vm86 *vm86)
+ */
+ENTRY(vm86_bioscall)
+ movl _vm86pcb,%edx /* data area, see vm86.c for layout */
+ movl 4(%esp),%eax
+ movl %eax,PCB_EIP(%edx) /* save argument pointer */
+ pushl %ebx
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushl %fs
+ pushl %gs
+
+#ifdef SMP
+ pushl %edx
+ ALIGN_LOCK /* Get global lock */
+ popl %edx
+#endif
+ movl _curproc,%ecx
+ pushl %ecx /* save _curproc value */
+ testl %ecx,%ecx
+ je 1f /* no process to save */
+
+#if NNPX > 0
+ cmpl %ecx,_npxproc /* do we need to save fp? */
+ jne 1f
+ movl P_ADDR(%ecx),%ecx
+ addl $PCB_SAVEFPU,%ecx
+ pushl %edx
+ call _npxsave
+ popl %edx /* recover our pcb */
+#endif
+
+1:
+ movl PCB_EBP(%edx),%ebx /* target frame location */
+ movl %ebx,%edi /* destination */
+ movl PCB_EIP(%edx),%esi /* source (set on entry) */
+ movl $21,%ecx /* sizeof(struct vm86frame)/4 */
+ cld
+ rep
+ movsl /* copy frame to new stack */
+
+ movl TF_TRAPNO(%ebx),%ebx
+ cmpl $256,%ebx
+ jb 1f /* no page frame to map */
+
+ andl $~PAGE_MASK,%ebx
+#if 0
+ orl $PG_V|PG_RW|PG_U,%ebx /* XXX assembler error?? */
+#endif
+ orl $0x7,%ebx
+ movl PCB_EBX(%edx),%eax /* va of vm86 page table */
+ movl %ebx,4(%eax) /* set vm86 PTE entry 1 */
+1:
+ movl _curpcb,%eax
+ pushl %eax /* save curpcb */
+ movl %edx,_curpcb /* set curpcb to vm86pcb */
+ movl $0,_curproc /* erase curproc */
+
+ movl _my_tr,%esi
+ leal _gdt(,%esi,8),%ebx /* entry in GDT */
+ movl 0(%ebx),%eax
+ movl %eax,PCB_FS(%edx) /* save first word */
+ movl 4(%ebx),%eax
+ andl $~0x200, %eax /* flip 386BSY -> 386TSS */
+ movl %eax,PCB_GS(%edx) /* save second word */
+
+ movl PCB_EXT(%edx),%edi /* vm86 tssd entry */
+ movl 0(%edi),%eax
+ movl %eax,0(%ebx)
+ movl 4(%edi),%eax
+ movl %eax,4(%ebx)
+ shll $3,%esi /* GSEL(entry, SEL_KPL) */
+ ltr %si
+
+ movl %cr3,%eax
+ pushl %eax /* save address space */
+#ifdef SMP
+ movl _my_idlePTD,%ecx
+#else
+ movl _IdlePTD,%ecx
+#endif
+ movl %ecx,%ebx
+ addl $KERNBASE,%ebx /* va of Idle PTD */
+ movl 0(%ebx),%eax
+ pushl %eax /* old ptde != 0 when booting */
+ pushl %ebx /* keep for reuse */
+
+ movl %esp,PCB_ESP(%edx) /* save current stack location */
+
+ movl PCB_ESI(%edx),%eax /* mapping for vm86 page table */
+ movl %eax,0(%ebx) /* ... install as PTD entry 0 */
+
+ movl %ecx,%cr3 /* new page tables */
+ movl PCB_EBP(%edx),%esp /* switch to new stack */
+
+ call _vm86_prepcall /* finish setup */
+
+ movl $1,_in_vm86call /* set flag for trap() */
+
+ /*
+ * Return via _doreti
+ */
+#ifdef SMP
+ ECPL_LOCK
+#ifdef CPL_AND_CML
+#error Not ready for CPL_AND_CML
+#endif
+ pushl _cpl /* cpl to restore */
+ ECPL_UNLOCK
+#else
+ pushl _cpl /* cpl to restore */
+#endif
+ subl $4,%esp /* dummy unit */
+ MPLOCKED incb _intr_nesting_level
+ MEXITCOUNT
+ jmp _doreti
+
+
+/*
+ * vm86_biosret(struct trapframe_vm86 *vm86)
+ */
+ENTRY(vm86_biosret)
+ movl _vm86pcb,%edx /* data area */
+
+ movl 4(%esp),%esi /* source */
+ movl PCB_EIP(%edx),%edi /* destination */
+ movl $21,%ecx /* size */
+ cld
+ rep
+ movsl /* copy frame to original frame */
+
+ movl PCB_ESP(%edx),%esp /* back to old stack */
+ popl %ebx /* saved va of Idle PTD */
+ popl %eax
+ movl %eax,0(%ebx) /* restore old pte */
+ popl %eax
+ movl %eax,%cr3 /* install old page table */
+
+ movl $0,_in_vm86call /* reset trapflag */
+ movl PCB_EBX(%edx),%ebx /* va of vm86 page table */
+ movl $0,4(%ebx) /* ...clear entry 1 */
+
+ movl _my_tr,%esi
+ leal _gdt(,%esi,8),%ebx /* entry in GDT */
+ movl PCB_FS(%edx),%eax
+ movl %eax,0(%ebx) /* restore first word */
+ movl PCB_GS(%edx),%eax
+ movl %eax,4(%ebx) /* restore second word */
+ shll $3,%esi /* GSEL(entry, SEL_KPL) */
+ ltr %si
+
+ popl _curpcb /* restore curpcb/curproc */
+ popl _curproc
+ movl TF_TRAPNO(%edx),%eax /* return (trapno) */
+
+ popl %gs
+ popl %fs
+ popl %edi
+ popl %esi
+ popl %ebp
+ popl %ebx
+ ret /* back to our normal program */
diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c
index 8ac19b1..b157bb6 100644
--- a/sys/i386/i386/vm_machdep.c
+++ b/sys/i386/i386/vm_machdep.c
@@ -38,7 +38,7 @@
*
* from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91
* Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
- * $Id: vm_machdep.c,v 1.103 1998/03/14 03:02:15 tegge Exp $
+ * $Id: vm_machdep.c,v 1.104 1998/03/17 09:10:05 kato Exp $
*/
#include "npx.h"
@@ -65,6 +65,10 @@
#ifdef SMP
#include <machine/smp.h>
#endif
+#ifdef VM86
+#include <machine/pcb_ext.h>
+#include <machine/vm86.h>
+#endif
#include <vm/vm.h>
#include <vm/vm_param.h>
@@ -599,7 +603,11 @@ cpu_fork(p1, p2)
* syscall. This copies the user mode register values.
*/
p2->p_md.md_regs = (struct trapframe *)
+#ifdef VM86
+ ((int)p2->p_addr + UPAGES * PAGE_SIZE - 16) - 1;
+#else
((int)p2->p_addr + UPAGES * PAGE_SIZE) - 1;
+#endif /* VM86 */
*p2->p_md.md_regs = *p1->p_md.md_regs;
/*
diff --git a/sys/i386/include/vm86.h b/sys/i386/include/vm86.h
index 127c951..4489c40 100644
--- a/sys/i386/include/vm86.h
+++ b/sys/i386/include/vm86.h
@@ -26,39 +26,12 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: vm86.h,v 1.3 1997/08/28 14:36:56 jlemon Exp $
+ * $Id: vm86.h,v 1.4 1997/11/20 18:43:55 bde Exp $
*/
#ifndef _MACHINE_VM86_H_
#define _MACHINE_VM86_H_ 1
-struct vm86_kernel {
- caddr_t vm86_intmap; /* interrupt map */
- u_long vm86_eflags; /* emulated flags */
- int vm86_has_vme; /* VME support */
- int vm86_inited; /* we were initialized */
- int vm86_debug;
-};
-
-struct i386_vm86_args {
- int sub_op; /* sub-operation to perform */
- char *sub_args; /* args */
-};
-
-#define VM86_INIT 1
-#define VM86_SET_VME 2
-#define VM86_GET_VME 3
-
-struct vm86_init_args {
- int debug; /* debug flag */
- int cpu_type; /* cpu type to emulate */
- u_char int_map[32]; /* interrupt map */
-};
-
-struct vm86_vme_args {
- int state; /* status */
-};
-
/* standard register representation */
typedef union {
u_long r_ex;
@@ -76,8 +49,8 @@ typedef union {
/* layout must match definition of struct trapframe_vm86 in <machine/frame.h> */
struct vm86frame {
- int :32; /* kernel ES */
- int :32; /* kernel DS */
+ int kernel_es;
+ int kernel_ds;
reg86_t edi;
reg86_t esi;
reg86_t ebp;
@@ -86,8 +59,8 @@ struct vm86frame {
reg86_t edx;
reg86_t ecx;
reg86_t eax;
- int :32; /* trapno */
- int :32; /* err */
+ int vmf_trapno;
+ int vmf_err;
reg86_t eip;
reg86_t cs;
reg86_t eflags;
@@ -97,7 +70,21 @@ struct vm86frame {
reg86_t ds;
reg86_t fs;
reg86_t gs;
+#define vmf_ah eax.r_b.r_h
+#define vmf_al eax.r_b.r_l
+#define vmf_ax eax.r_w.r_x
+#define vmf_eax eax.r_ex
+#define vmf_bx ebx.r_w.r_x
+#define vmf_ebx ebx.r_ex
+#define vmf_cx ecx.r_w.r_x
+#define vmf_ecx ecx.r_ex
+#define vmf_dx edx.r_w.r_x
+#define vmf_edx edx.r_ex
+#define vmf_si esi.r_w.r_x
+#define vmf_di edi.r_w.r_x
#define vmf_cs cs.r_w.r_x
+#define vmf_ds ds.r_w.r_x
+#define vmf_es es.r_w.r_x
#define vmf_ss ss.r_w.r_x
#define vmf_sp esp.r_w.r_x
#define vmf_ip eip.r_w.r_x
@@ -105,8 +92,52 @@ struct vm86frame {
#define vmf_eflags eflags.r_ex
};
+#define VM_USERCHANGE (PSL_USERCHANGE | PSL_RF)
+#define VME_USERCHANGE (VM_USERCHANGE | PSL_VIP | PSL_VIF)
+
+struct vm86_kernel {
+ caddr_t vm86_intmap; /* interrupt map */
+ u_long vm86_eflags; /* emulated flags */
+ int vm86_has_vme; /* VME support */
+ int vm86_inited; /* we were initialized */
+ int vm86_debug;
+ caddr_t vm86_sproc; /* address of sproc */
+};
+
+struct i386_vm86_args {
+ int sub_op; /* sub-operation to perform */
+ char *sub_args; /* args */
+};
+
+#define VM86_INIT 1
+#define VM86_SET_VME 2
+#define VM86_GET_VME 3
+#define VM86_INTCALL 4
+
+struct vm86_init_args {
+ int debug; /* debug flag */
+ int cpu_type; /* cpu type to emulate */
+ u_char int_map[32]; /* interrupt map */
+};
+
+struct vm86_vme_args {
+ int state; /* status */
+};
+
+struct vm86_intcall_args {
+ int intnum;
+ struct vm86frame vmf;
+};
+
+extern int in_vm86call;
+
struct proc;
extern int vm86_emulate __P((struct vm86frame *));
extern int vm86_sysarch __P((struct proc *, char *));
+extern void vm86_trap __P((struct vm86frame *));
+extern int vm86_intcall __P((int, struct vm86frame *));
+extern int vm86_datacall __P((int, struct vm86frame *, char *, int,
+ u_short *, u_short *));
+extern void initial_bioscalls __P((u_int *, u_int *));
#endif /* _MACHINE_VM86_H_ */
diff --git a/sys/i386/isa/ipl.s b/sys/i386/isa/ipl.s
index bd586ee..9b3979c 100644
--- a/sys/i386/isa/ipl.s
+++ b/sys/i386/isa/ipl.s
@@ -36,7 +36,7 @@
*
* @(#)ipl.s
*
- * $Id: ipl.s,v 1.19 1997/12/15 02:18:35 tegge Exp $
+ * $Id: ipl.s,v 1.20 1998/03/03 22:56:29 tegge Exp $
*/
@@ -159,6 +159,8 @@ doreti_exit:
/* XXX CPL_AND_CML needs work */
#error not ready for vm86
#endif
+ cmpl $1,_in_vm86call
+ je 1f /* want cpl == SWI_AST_PENDING */
/*
* XXX
* Sometimes when attempting to return to vm86 mode, cpl is not
@@ -342,6 +344,10 @@ doreti_swi:
ALIGN_TEXT
swi_ast:
addl $8,%esp /* discard raddr & cpl to get trap frame */
+#ifdef VM86
+ cmpl $1,_in_vm86call
+ je 1f /* stay in kernel mode */
+#endif
testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
je swi_ast_phantom
swi_ast_user:
@@ -364,6 +370,7 @@ swi_ast_phantom:
*/
testl $PSL_VM,TF_EFLAGS(%esp)
jne swi_ast_user
+1:
#endif /* VM86 */
/*
* These happen when there is an interrupt in a trap handler before
diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c
index 79715f5..5e1bb32 100644
--- a/sys/kern/subr_trap.c
+++ b/sys/kern/subr_trap.c
@@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)trap.c 7.4 (Berkeley) 5/13/91
- * $Id: trap.c,v 1.121 1998/02/04 22:32:12 eivind Exp $
+ * $Id: trap.c,v 1.122 1998/02/06 12:13:10 eivind Exp $
*/
/*
@@ -225,6 +225,35 @@ restart:
type = frame.tf_trapno;
code = frame.tf_err;
+#ifdef VM86
+ if (in_vm86call) {
+ if (frame.tf_eflags & PSL_VM &&
+ (type == T_PROTFLT || type == T_STKFLT)) {
+ i = vm86_emulate((struct vm86frame *)&frame);
+ if (i != 0)
+ /*
+ * returns to original process
+ */
+ vm86_trap((struct vm86frame *)&frame);
+ return;
+ }
+ switch (type) {
+ /*
+ * these traps want either a process context, or
+ * assume a normal userspace trap.
+ */
+ case T_PROTFLT:
+ case T_SEGNPFLT:
+ trap_fatal(&frame);
+ return;
+ case T_TRCTRAP:
+ type = T_BPTFLT; /* kernel breakpoint */
+ /* FALL THROUGH */
+ }
+ goto kernel_trap; /* normal kernel trap handling */
+ }
+#endif
+
if ((ISPL(frame.tf_cs) == SEL_UPL) || (frame.tf_eflags & PSL_VM)) {
/* user trap */
@@ -356,6 +385,9 @@ restart:
break;
}
} else {
+#ifdef VM86
+kernel_trap:
+#endif
/* kernel trap */
switch (type) {
OpenPOWER on IntegriCloud