4 ;******************************************************************************
5 title VMTRAP
- 386 Virtual Mode interrupt handler routines
6 ;******************************************************************************
8 ; (C) Copyright MICROSOFT Corp. 1986
10 ; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver
12 ; Module: VMTRAP - 386 Virtual Mode interrupt handler routines
16 ; Date: January 26, 1986
20 ;******************************************************************************
24 ; DATE REVISION DESCRIPTION
25 ; -------- -------- ------------------------------------------------------
27 ; 02/05/86 A- Added int 15h trap to move block function.
28 ; 05/12/86 A Cleanup and segment reorganization
29 ; 06/19/86 0.01 Added emul_reflect entry point for preserving
30 ; IF and TF flags bits on reflections done by
31 ; instruction emulators.
32 ; 06/28/86 0.02 Name change from MEMM386 to MEMM
33 ; 07/20/88 Removed debugger codes (pc)
35 ;******************************************************************************
37 ; Functional Description:
39 ; This module contains the interrupt and trap handlers for Virtual DOS.
41 ; Note that a conscious decision has been made to attempt to field the
42 ; Master 8259 interrupts at the normal PC location (vectors 8 - F). The
43 ; main problem is that these overlap CPU exception vectors. While the
44 ; 8259 base vector address could be changed (there's lots of room in the
45 ; IDT, since we're fielding S/W INTs through GP 13), the primary reason
46 ; for not doing so is to avoid any potential trouble with an application
47 ; reprogramming the 8259. We don't know of any that do, and you could
48 ; trap them if they tried anyway.
50 ; "to do:" marks potential holes/things to consider
52 ;******************************************************************************
53 .lfcond
; list false conditionals
56 ;******************************************************************************
57 ; P U B L I C D E C L A R A T I O N S
58 ;******************************************************************************
60 public VmTrap
; module label
100 ;******************************************************************************
101 ; E X T E R N A L R E F E R E N C E S
102 ;******************************************************************************
105 extrn VmFault
:near ; V Mode GP fault handler (VMINST)
106 extrn ErrHndlr
:near ; Error Handler (ERRHNDLR)
107 extrn DisableNMI
:near ; Disable NMI for NMI trap handler
110 ;******************************************************************************
111 ; I N C L U D E F I L E S
112 ;******************************************************************************
122 ;******************************************************************************
123 ; L O C A L C O N S T A N T S
124 ;******************************************************************************
129 ProcessExcep
macro ExcepNum
135 ;******************************************************************************
136 ; S E G M E N T D E F I N I T I O N
137 ;******************************************************************************
139 ABS0
segment at 0000h
142 ;------------------------------------------------------------------------------
144 assume
cs:_TEXT
, ds:NOTHING
, es:NOTHING
, ss:NOTHING
150 ;******************************************************************************
151 ; CPU: Divide error fault
153 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
154 ; No error code on stack
155 ; EXIT: to handler or debugger as appropriate
158 ;------------------------------------------------------------------------------
162 test [bp.VTFO
+VMTF_EFLAGShi
],2 ; Q: client in Virtual Mode ?
163 jz vmt0_dexit
; N: exit to debugger
164 push 0000 ; Y: interrupt 00
165 jmp hw_int
; reflect it to virtual mode
170 ;******************************************************************************
173 ; Traps from Virtual mode are reflected to virtual mode. Unfortunately
174 ; this breaks the debugger's ability to GO and TRACE the VM program.
176 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
177 ; No error code on stack
178 ; EXIT: to handler or debugger as appropriate
181 ;------------------------------------------------------------------------------
185 test [bp.VTFO
+VMTF_EFLAGShi
],2 ; Q: client in Virtual Mode ?
186 jz vmt1_dexit
; N: exit to debugger
187 push 0001 ; Y: interrupt 01
188 jmp hw_int
; reflect it to virtual mode
193 ;******************************************************************************
196 ; For now, this always traps to the debugger. It's a general purpose hook
197 ; to let the debugger get control via an NMI button.
199 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
200 ; No error code on stack
201 ; EXIT: to handler or debugger as appropriate
204 ;------------------------------------------------------------------------------
211 test [bp.VTFO
+VMTF_EFLAGShi
],2 ; Q: client in Virtual Mode ?
212 jz vmt2_parity
; N: error/debug trap
213 ; Y: reflect it/debugger
221 ;******************************************************************************
222 ; CPU: Breakpoint trap (INT 3 instruction)
224 ; Traps from Virtual mode are reflected to virtual mode. Unfortunately
225 ; this breaks the debugger's ability to GO and TRACE the VM program.
227 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
228 ; No error code on stack
229 ; EXIT: to handler or debugger as appropriate
232 ;------------------------------------------------------------------------------
237 ;******************************************************************************
238 ; CPU: Overflow trap (INTO instruction)
240 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
241 ; No error code on stack
242 ; EXIT: to handler or debugger as appropriate
245 ;------------------------------------------------------------------------------
251 ;******************************************************************************
252 ; CPU: Array bounds fault
254 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
255 ; No error code on stack
256 ; EXIT: to handler or debugger as appropriate
259 ;------------------------------------------------------------------------------
263 test [bp.VTFO
+VMTF_EFLAGShi
],2 ; Q: client in Virtual Mode ?
264 jz vmt5_dexit
; N: exit to debugger
265 push 0005 ; Y: interrupt 01
266 jmp hw_int
; reflect it to virtual mode
268 ProcessExcep ErrBounds
271 ;******************************************************************************
272 ; CPU: Invalid Opcode fault
274 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
275 ; No error code on stack
276 ; EXIT: to handler or debugger as appropriate
280 ; add Invalid instruction emulator ??? (specifically LOCK prefix)
282 ;------------------------------------------------------------------------------
284 push 0 ; align stack with error offset
288 test [bp.VTFOE
+VMTF_EFLAGShi
],2 ; Q: client in Virtual Mode ?
289 jz vmt6_dexit
; N: exit to debugger
290 jmp VmFault
; Y: enter VM 06 Invalid handler
293 ProcessExcep ErrOpCode
296 ;******************************************************************************
297 ; CPU: Coprocessor not present fault
299 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
300 ; No error code on stack
301 ; EXIT: to handler or debugger as appropriate
304 ;------------------------------------------------------------------------------
308 test [bp.VTFO
+VMTF_EFLAGShi
],2 ; Q: client in Virtual Mode ?
309 jz vmt7_dexit
; N: exit to debugger
310 push 0007 ; Y: interrupt 07
311 jmp hw_int
; reflect it to virtual mode
313 ProcessExcep ErrCoPNA
317 ;******************************************************************************
319 ; H/W: IRQ0 - System timer
321 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
322 ; Error Code on stack = 0000
323 ; EXIT: to handler or debugger as appropriate
326 ;------------------------------------------------------------------------------
330 cmp sp,VMT_STACK
; Q: H/W interrupt from VM ?
331 jne vmt8_dexit
; N: exit to debugger
332 push 0008 ; Y: interrupt 8
333 jmp hw_int
; reflect it to virtual mode
335 ProcessExcep ErrDouble
339 ;******************************************************************************
340 ; CPU: (none for 386)
341 ; H/W: IRQ1 - Keyboard
343 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
344 ; No error code on stack
345 ; EXIT: to handler or debugger as appropriate
348 ;------------------------------------------------------------------------------
352 push 0009 ; Y: interrupt 9
353 jmp hw_int
; reflect it to virtual mode
356 ;******************************************************************************
357 ; CPU: Invalid TSS fault
358 ; H/W: IRQ2 - Cascade from slave 8259 (see INT 70-77)
359 ; (shouldn't get H/W interrupts here)
361 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
362 ; Error Code on stack = Selector
363 ; EXIT: to handler or debugger as appropriate
367 ; to do: someone could reprogram master 8259 - need to handle ?
368 ;------------------------------------------------------------------------------
374 ;******************************************************************************
375 ; CPU: Segment Not Present fault
378 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
379 ; Error Code on stack = Selector
380 ; EXIT: to handler or debugger as appropriate
383 ;------------------------------------------------------------------------------
387 test [bp.VTFO
+VMTF_EFLAGShi
],2 ; Q: client in Virtual Mode ?
388 jz vmtB_dexit
; N: exit to debugger
389 push 000Bh ; Y: interrupt 0B
390 jmp hw_int
; reflect it to virtual mode
392 ProcessExcep ErrSegNP
395 ;******************************************************************************
399 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
400 ; Error Code on stack = Selector or 0000
401 ; EXIT: to handler or debugger as appropriate
404 ;------------------------------------------------------------------------------
408 test [bp.VTFO
+VMTF_EFLAGShi
],2 ; Q: client in Virtual Mode ?
409 jz vmtC_dexit
; N: exit to debugger
410 push 000Ch ; Y: interrupt 0C
411 jmp hw_int
; reflect it to virtual mode
413 ProcessExcep ErrStack
416 ;******************************************************************************
417 ; CPU: General Protection fault
418 ; H/W: IRQ5 - Second parallel printer
420 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
421 ; Error Code on stack = Selector or 0000
422 ; EXIT: to handler or debugger as appropriate
425 ;------------------------------------------------------------------------------
429 cmp sp,VMT_STACK
; Q: H/W interrupt from VM ?
430 jne vmtD_1
; N: continue
431 push 000Dh ; Y: interrupt vector 0Dh
432 jmp hw_int
; reflect it to virtual mode
434 ; Here we have a GP fault that was not a H/W interrupt 13 from VM.
437 cmp sp,VMTERR_STACK
; Q: 'normal' exception w/error code ?
438 jne vmtD_dexit
; N: what the hell was it ???? - exit
439 jmp VmFault
; Y: enter VM GP fault handler
440 ; (fall thru to debugger)
445 ;******************************************************************************
447 ; H/W: IRQ6 - diskette interrupt
449 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
450 ; Error Code on stack = type of fault
451 ; EXIT: to handler or debugger as appropriate
454 ;------------------------------------------------------------------------------
458 cmp sp,VMT_STACK
; Q: H/W interrupt from VM ?
459 jne vmtE_dexit
; N: exit to debugger
460 push 000Eh ; Y: interrupt vector 0Eh
461 jmp hw_int
; reflect it to virtual mode
466 ;******************************************************************************
468 ; H/W: IRQ7 - parallel printer
470 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
471 ; No error code on stack
472 ; EXIT: to handler or debugger as appropriate
475 ;------------------------------------------------------------------------------
479 push 000Fh ; push interrupt number
480 jmp hw_int
; enter common H/W interrupt handler
483 ;******************************************************************************
484 ; CPU: Coprocessor Error - GOES TO NOT PRESENT FAULT IN DEBUGGER FOR NOW
486 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
487 ; No error code on stack
488 ; EXIT: to handler or debugger as appropriate
491 ;------------------------------------------------------------------------------
493 ProcessExcep ErrCoPerr
496 ;******************************************************************************
497 ; VmTrap5x - Handlers for hardware interrupts. Sometimes the master 8259
500 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
501 ; EXIT: EBP pushed on stack
502 ; BP = normal stack frame pointer
503 ; Interrupt number pushed on stack
506 ;------------------------------------------------------------------------------
509 mov bp,sp ; set up BP frame pointer
511 jmp short hw_int
; enter common code
514 ;------------------------------------------------------------------------------
517 mov bp,sp ; set up BP frame pointer
519 jmp short hw_int
; enter common code
522 ;------------------------------------------------------------------------------
525 mov bp,sp ; set up BP frame pointer
527 jmp short hw_int
; enter common code
530 ;------------------------------------------------------------------------------
533 mov bp,sp ; set up BP frame pointer
535 jmp short hw_int
; enter common code
538 ;------------------------------------------------------------------------------
541 mov bp,sp ; set up BP frame pointer
543 jmp short hw_int
; enter common code
546 ;------------------------------------------------------------------------------
549 mov bp,sp ; set up BP frame pointer
551 jmp short hw_int
; enter common code
554 ;------------------------------------------------------------------------------
557 mov bp,sp ; set up BP frame pointer
559 jmp short hw_int
; enter common code
562 ;------------------------------------------------------------------------------
565 mov bp,sp ; set up BP frame pointer
567 jmp short hw_int
; enter common code
570 ;******************************************************************************
571 ; VmTrap7x - handlers for hardware interrupts from the slave 8259
573 ; ENTRY: 386 Protected Mode via 386 Interrupt gate
574 ; EXIT: EBP pushed on stack
575 ; BP = normal stack frame pointer
576 ; Interrupt number pushed on stack
579 ;------------------------------------------------------------------------------
582 mov bp,sp ; set up BP frame pointer
584 jmp short hw_int
; enter common code
587 ;------------------------------------------------------------------------------
590 mov bp,sp ; set up BP frame pointer
592 jmp short hw_int
; enter common code
595 ;------------------------------------------------------------------------------
598 mov bp,sp ; set up BP frame pointer
600 jmp short hw_int
; enter common code
603 ;------------------------------------------------------------------------------
606 mov bp,sp ; set up BP frame pointer
608 jmp short hw_int
; enter common code
611 ;------------------------------------------------------------------------------
614 mov bp,sp ; set up BP frame pointer
616 jmp short hw_int
; enter common code
619 ;------------------------------------------------------------------------------
622 mov bp,sp ; set up BP frame pointer
624 jmp short hw_int
; enter common code
627 ;------------------------------------------------------------------------------
630 mov bp,sp ; set up BP frame pointer
632 jmp short hw_int
; enter common code
635 ;------------------------------------------------------------------------------
638 mov bp,sp ; set up BP frame pointer
640 jmp short hw_int
; enter common code
644 ;******************************************************************************
645 ; HW_INT - common handler for hardware interrupts. The interrupt is
646 ; reflected directly to the appropriate Real Mode (Virtual) handler.
647 ; This entry point clear the trace flag (TF) and int flag (IF), since
648 ; a h/w interrupt would (NOTE: INT n and INTO instructions also clear
649 ; TF and IF - so this entry is suitable for reflecting these also).
651 ; EMUL_REFLECT - entry point for reflecting emulations.
652 ; This entry point does not clear the trace flag (TF) and int flag (IF).
654 ; 386 interrupt gate switched us to the Ring 0 stack on the way in
655 ; from Virtual Mode and pushed 32-bit values as follows:
657 ; hiword loword offset (in addition to EBP push)
658 ; +------+------+ <-------- Top of 'kernel' stack
659 ; | 0000 | GS | +32 (decimal)
676 ; +------+------+ <-------- Ring 0 SS:SP
678 ; +-------------+ <-------- Ring 0 SS:BP
680 ; The object of this routine is to massage the trap stack frame (above)
681 ; and build a 'real mode' stack frame for the virtual mode client so that
682 ; we can transfer control to virtual mode at the address specified in
683 ; the appropriate real mode IDT vector. The client's IRET out of the
684 ; interrupt routine will proceed normally (assuming we're letting him
685 ; run with IOPL = 3). Since we're fielding the trap from Virtual Mode,
686 ; we assume the high word of ESP and EIP is 0000.
688 ; +-------+ <-------- Client's current SS:SP
694 ; +-------+ <-------- Client's SS:SP when we let him have control
696 ; Assume entry from Virtual Mode, for now. We shouldn't be getting entered
697 ; here except via Hardware interrupt, so no sanity checks are performed.
699 ; ENTRY: 386 Protected Mode
700 ; BP -> standard frame
701 ; EBP and Interrupt number have been pushed onto stack
702 ; EXIT: via IRET to VM86 program
703 ; appropriate real mode IRET set up @ client's SS:SP
704 ; USED: (none) (note that DS & ES are free to use - saved during trap)
707 ; to do: Need to check for entry mode ?
708 ;------------------------------------------------------------------------------
712 mov si,[bp.VTFO
+VMTF_EFLAGS
] ; SI = saved low word of EFLAGS
714 ; *** clear IF bit and Trace Flag on flags for reflect, but leave them
715 ; unchanged for the flags on the IRET stack we build on the
718 and [bp.VTFO
+VMTF_EFLAGS
],not 300h
; clear IF and TF
721 ; Build a selector (VM1_GSEL) to client's stack. VM1_GSEL is already set
722 ; up with limit (0FFFFh) and access (D_DATA0), so just fill in the base.
724 HwTabUnlock
; disable HW protection on high ram
725 mov bx,GDTD_GSEL
; get GDT data alias
726 mov ds,bx ; DS -> GDT
727 mov bx,[bp.VTFO
+VMTF_SS
] ; BX = VM SS (segment form)
728 shl bx,4 ; BX = low 16 bits of base
729 mov ds:[VM1_GSEL
+2],bx ; place in descriptor
730 mov bx,[bp.VTFO
+VMTF_SS
] ; BX = VM SS (again)
731 shr bx,4 ; BH = high 8 bits of base
732 mov ds:[VM1_GSEL
+4],bh ; place in descriptor
734 ; Adjust client's SP to make room for building his IRET frame
736 sub word ptr [bp.VTFO
+VMTF_ESP
],6 ; adjust client's SP
738 mov ds, bx ; DS = VM stack segment
740 mov bx,si ; BX = low word of client's EFLAGS
742 mov si,[bp.VTFO
+VMTF_ESP
] ; DS:SI = pointer to client's frame
744 ; Move low 16 bits of Flags, CS, and EIP from IRET frame to client stack frame
746 mov ds:[si.4],bx ; to client's flags
747 mov bx,[bp.VTFO
+VMTF_CS
] ;
748 mov ds:[si.2],bx ; to client's CS
749 mov bx,[bp.VTFO
+VMTF_EIP
] ; low word of EIP
750 mov ds:[si.0],bx ; to client's IP
752 ; Replace low 16 bits of IRET frame CS:EIP with vector from real mode IDT
754 mov bx,[bp-2] ; get the interrupt vector
755 shl bx,2 ; BX = BX * 4 (vector table index)
756 mov si,RM_IDT_GSEL
; get real mode IDT alias
757 mov ds,si ; DS -> Real Mode IDT
759 mov [bp.VTFO
+VMTF_EIP
],si ; move the IP
761 mov [bp.VTFO
+VMTF_CS
],si ; move the CS
763 ; 32-bit IRET back to client
765 HwTabLock
; enable HW protection on high ram
766 pop si ; restore local regs
768 pop bp ; throw away fake interrupt number
771 iret ; *** RETURN *** to client
774 ;******************************************************************************
776 ;******************************************************************************
778 ; emulation relfection entry point - don't mess with client's flags
780 emul_reflect
label near
781 push bx ; local registers
783 mov si,[bp.VTFO
+VMTF_EFLAGS
] ; SI = saved low word of EFLAGS
788 _TEXT ends
; end of segment