mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5217 lines
154 KiB
5217 lines
154 KiB
PAGE ,132
|
|
TITLE DXINTR.ASM -- Dos Extender Interrupt Reflector
|
|
|
|
; Copyright (c) Microsoft Corporation 1988-1991. All Rights Reserved.
|
|
|
|
;****************************************************************
|
|
;* *
|
|
;* DXINTR.ASM - Dos Extender Interrupt Reflector *
|
|
;* *
|
|
;****************************************************************
|
|
;* *
|
|
;* Revision History: *
|
|
;* *
|
|
;* *
|
|
;* 09/13/90 earleh Fault handlers Ring 0 *
|
|
;* 09/06/90 earleh Fault handlers DPMI compliant *
|
|
;* PIC remapping no longer required *
|
|
;* 08/08/90 earleh DOSX and client privilege ring determined *
|
|
;* by equate in pmdefs.inc *
|
|
;* 05/09/90 jimmat Started VCPI changes. *
|
|
;* 04/02/90 jimmat Added PM Int 70h handler. *
|
|
;* 01/08/90 jimmat Don't allow nested PS/2 mouse interrupts *
|
|
;* (later removed!) *
|
|
;* 09/15/89 jimmat Support for 'Classic' HP Vectras which *
|
|
;* have 3 8259 interrupt controllers *
|
|
;* 07/28/89 jimmat Save A20 state when reflecting an int to *
|
|
;* protected mode, removed Int 30h handler *
|
|
;* that did code patch-ups, point debugger *
|
|
;* to faulting instruction, not Int 3. *
|
|
;* 07/13/89 jimmat Improved termination due to faults when *
|
|
;* not running under a debugger--also ifdef'd *
|
|
;* out code to dynamically fixup code seg *
|
|
;* references on GP faults *
|
|
;* 06/05/89 jimmat Ints 0h-1Fh are now vectored through a 2nd *
|
|
;* table. This allows Wdeb386 interaction *
|
|
;* more like Windows/386. *
|
|
;* 05/23/89 jimmat Added wParam & lParam to interrupt frame. *
|
|
;* 05/07/89 jimmat Added XMScontrol function to map protected *
|
|
;* mode XMS requests to real mode driver. *
|
|
;* 05/02/89 jimmat 8259 interrupt mask saved around changing *
|
|
;* of hardware interrupt base *
|
|
;* 04/24/89 jimmat Added support for PS/2 Int 15h/C2h/07 Set *
|
|
;* Pointing Device Handler Address function *
|
|
;* 04/12/89 jimmat Added PMIntr24 routine to support PM *
|
|
;* Critical Error Handlers *
|
|
;* 03/15/89 jimmat Added INT 31h LDT/heap interface a la *
|
|
;* Windows/386 *
|
|
;* 03/14/89 jimmat Changes to run child in ring 1 with LDT *
|
|
;* 02/24/89 (GeneA): fixed problem in IntEntryVideo and *
|
|
;* IntExitVideo for processing function 10h subfunction *
|
|
;* for reading and writing the VGA palette. *
|
|
;* 02/22/89 (GeneA): added handlers for Int 10h, Int 15h, and *
|
|
;* Int 33h. Added support for more general mechanism for *
|
|
;* handling interrupts require special servicing and *
|
|
;* allowing nesting of these interrupts. Allocation and *
|
|
;* deallocation of stack frames is supported to allow *
|
|
;* nested paths through the interrupt reflection code to *
|
|
;* a depth of 8. *
|
|
;* There is still a problem that if an interrupt handler *
|
|
;* is using a static buffer to transfer data, another *
|
|
;* interrupt that uses the same static buffer could come *
|
|
;* in and trash it. Solving the problem in a completely *
|
|
;* general way would require having a buffer allocation *
|
|
;* deallocation scheme for doing the transfers between *
|
|
;* real mode memory and protected mode memory. *
|
|
;* 02/14/89 (GeneA): added code in TrapGP to print error msg *
|
|
;* and quit when running a non-debugging version. *
|
|
;* 02/10/89 (GeneA): changed Dos Extender from small model to *
|
|
;* medium model. Added function LoaderTrap to handle *
|
|
;* loader interrupts when the program contains overlays. *
|
|
;* 11/20/88 (GeneA): changed both RM and PM interrupt reflector*
|
|
;* routines to pass the flags returned by the ISR back to *
|
|
;* the originator of the interrupt, rather than returning *
|
|
;* the original flags. *
|
|
;* 10/28/88 (GeneA): created *
|
|
; 18-Dec-1992 sudeepb Changed cli/sti to faster FCLI/FSTI
|
|
;* *
|
|
;****************************************************************
|
|
|
|
.286p
|
|
.287
|
|
|
|
; -------------------------------------------------------
|
|
; INCLUDE FILE DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
.xlist
|
|
.sall
|
|
include segdefs.inc
|
|
include gendefs.inc
|
|
include pmdefs.inc
|
|
include interupt.inc
|
|
if VCPI
|
|
include dxvcpi.inc
|
|
endif
|
|
IFDEF ROM
|
|
include dxrom.inc
|
|
ENDIF
|
|
ifdef wow
|
|
include vdmtib.inc
|
|
endif
|
|
.list
|
|
include intmac.inc
|
|
include stackchk.inc
|
|
include bop.inc
|
|
|
|
; -------------------------------------------------------
|
|
; GENERAL SYMBOL DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
DS_ForcedGO equ 0F003h ;Wdeb386 go with breakpoint command
|
|
DebOut_Int equ 41h ;Wdeb386 pMode interface Interrupt
|
|
|
|
; Offsets to fields in DOSX header for DOS allocated memory blocks
|
|
|
|
MemCookie equ 0
|
|
MemSelector equ 2
|
|
MemSegment equ 4
|
|
MemParas equ 6
|
|
MemSelCount equ 8
|
|
|
|
MemGoodCookie equ 'SF' ;memory header magic cookie value
|
|
|
|
; -------------------------------------------------------
|
|
; EXTERNAL SYMBOL DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
extrn PMIntr13:NEAR
|
|
extrn PmIntrDos:NEAR
|
|
extrn EnterRealMode:NEAR
|
|
extrn EnterProtectedMode:NEAR
|
|
extrn ParaToLinear:NEAR
|
|
externFP NSetSegmentDscr
|
|
extrn GetSegmentAddress:NEAR
|
|
extrn DupSegmentDscr:NEAR
|
|
extrn ParaToLDTSelector:NEAR
|
|
extrn FreeSelector:NEAR
|
|
extrn FreeSelectorBlock:NEAR
|
|
extrn AllocateSelector:NEAR
|
|
extrn AllocateSelectorBlock:NEAR
|
|
|
|
; -------------------------------------------------------
|
|
; DATA SEGMENT DEFINITIONS
|
|
; -------------------------------------------------------
|
|
|
|
DXDATA segment
|
|
|
|
extrn fDebug:BYTE
|
|
extrn selIDT:WORD
|
|
extrn pmusrss:WORD
|
|
extrn pmusrsp:WORD
|
|
ifdef NOT_NTVDM_NOT
|
|
extrn fHPVectra:BYTE
|
|
endif
|
|
extrn idCpuType:WORD
|
|
extrn npXfrBuf0:WORD
|
|
extrn npXfrBuf1:WORD
|
|
extrn rgbXfrBuf0:BYTE
|
|
extrn rgbXfrBuf1:BYTE
|
|
extrn selPSPChild:WORD
|
|
extrn fFaultAbort:BYTE
|
|
extrn lpfnXMSFunc:DWORD
|
|
extrn Int28Filter:WORD
|
|
extrn A20EnableCount:WORD
|
|
|
|
if DEBUG
|
|
extrn fTraceReflect:WORD
|
|
endif
|
|
|
|
if VCPI
|
|
extrn fVCPI:BYTE
|
|
endif
|
|
|
|
IFDEF ROM
|
|
extrn segDXData:WORD
|
|
extrn segDXCode:WORD
|
|
ENDIF
|
|
IFDEF WOW
|
|
extrn DpmiFlags:WORD
|
|
ENDIF
|
|
|
|
;
|
|
; Variables used to store register values while mode switching.
|
|
|
|
public regUserSS, regUserSP, regUserFL, regUserAX, regUserDS
|
|
public regUserES
|
|
|
|
regUserSS dw ?
|
|
regUserSP dw ?
|
|
regUserCS dw ?
|
|
regUserIP dw ?
|
|
regUserFL dw ?
|
|
regUserAX dw ?
|
|
regUserDS dw ?
|
|
regUserES dw ?
|
|
pfnReturnAddr dw ?
|
|
|
|
Int28Count dw -1 ;Count of idle Int 28h's not reflected to RM
|
|
|
|
;
|
|
; Far pointer to the user's mouse callback function.
|
|
|
|
public lpfnUserMouseHandler
|
|
|
|
lpfnUserMouseHandler dd 0 ;Entry point to the users mouse handler
|
|
cbMouseState dw 0 ;size of mouse state buffer in bytes
|
|
|
|
|
|
; Far pointer to PS/2 Pointing device handler address
|
|
|
|
public lpfnUserPointingHandler
|
|
|
|
lpfnUserPointingHandler dd 0 ;Sel:Off to user's handler
|
|
|
|
public PMInt24Handler
|
|
|
|
PMInt24Handler dd 0 ;Address of protect mode Int 24h handler
|
|
ifdef WOW
|
|
dd 0 ; other half
|
|
endif
|
|
|
|
align 2
|
|
|
|
if DEBUG
|
|
extrn StackGuard:WORD
|
|
endif
|
|
extrn pbReflStack:WORD
|
|
extrn bReflStack:WORD
|
|
;
|
|
; This buffer contains the original real mode interrupt vectors. The
|
|
; PM->RM interrupt reflector uses the addresses in this vector as the
|
|
; address to receive control when it reflects an interrupt to real mode.
|
|
|
|
public rglpfnRmISR
|
|
|
|
align 2
|
|
rglpfnRmISR dd 256 dup (?)
|
|
|
|
;
|
|
; This buffer contains the real mode hardware interrupt vectors.
|
|
; If a hardware interrupt is hooked in protected mode, a reflector
|
|
; is put into the IVT. If we were trying to reflect down the real
|
|
; mode chain, we call these handlers if the IVT contains a reflector
|
|
;
|
|
public RmHwIsr
|
|
RmHwIsr dd 256 dup(0)
|
|
|
|
;
|
|
; This flag indicates if the hardware interrupts have been remapped.
|
|
public fHardwareIntMoved
|
|
fHardwareIntMoved db 0
|
|
|
|
ifdef SEG_FIXUP ;-----------------------------------------------
|
|
|
|
errGP dw ? ;this variable is used to hold the error
|
|
|
|
endif ;SEG_FIXUP ------------------------------------------------
|
|
|
|
|
|
; PMFaultVector is a table of selector:offsets for routines to process
|
|
; protected mode processor faults/traps/exceptions. If we don't handle
|
|
; the exception as an exception, we vector it through PMReservedEntryVector.
|
|
|
|
IFNDEF WOW
|
|
FltRtn macro off
|
|
dw DXPMCODE:off
|
|
dw SEL_DXPMCODE or STD_RING
|
|
endm
|
|
ELSE
|
|
FltRtn macro off
|
|
dw DXPMCODE:off
|
|
dw 0
|
|
dw SEL_DXPMCODE or STD_RING
|
|
dw 0
|
|
endm
|
|
ENDIF
|
|
public PMFaultVector
|
|
|
|
align 4
|
|
|
|
PMFaultVector label DWORD
|
|
IFNDEF WOW
|
|
FltRtn PMReservedEntryVector+3*0h ; int 0
|
|
FltRtn PMReservedEntryVector+3*1h ; int 1
|
|
FltRtn PMReservedEntryVector+3*2h ; int 2
|
|
FltRtn PMReservedEntryVector+3*3h ; int 3
|
|
FltRtn PMReservedEntryVector+3*4h ; int 4
|
|
FltRtn PMReservedEntryVector+3*5h ; int 5
|
|
FltRtn TrapInvalidOpcode ; int 6
|
|
FltRtn PMReservedEntryVector+3*7h ; int 7
|
|
FltRtn TrapDoubleFault ; int 8
|
|
FltRtn TrapExtensionOverrun ; int 9
|
|
FltRtn TrapInvalidTSS ; int A
|
|
FltRtn TrapSegmentNotPresent ; int b
|
|
FltRtn TrapStackOverrun ; int c
|
|
FltRtn TrapGP ; int d
|
|
FltRtn TrapPageFault ; int e
|
|
FltRtn PMReservedEntryVector+3*0Fh ; int f
|
|
FltRtn PMReservedEntryVector+3*10h ; int 10h
|
|
FltRtn PMReservedEntryVector+3*11h ; int 11h
|
|
FltRtn PMReservedEntryVector+3*12h ; int 12h
|
|
FltRtn PMReservedEntryVector+3*13h ; int 13h
|
|
FltRtn PMReservedEntryVector+3*14h ; int 14h
|
|
FltRtn PMReservedEntryVector+3*15h ; int 15h
|
|
FltRtn PMReservedEntryVector+3*16h ; int 16h
|
|
FltRtn PMReservedEntryVector+3*17h ; int 17h
|
|
FltRtn PMReservedEntryVector+3*18h ; int 18h
|
|
FltRtn PMReservedEntryVector+3*19h ; int 19h
|
|
FltRtn PMReservedEntryVector+3*1Ah ; int 1ah
|
|
FltRtn PMReservedEntryVector+3*1Bh ; int 1bh
|
|
FltRtn PMReservedEntryVector+3*1Ch ; int 1ch
|
|
FltRtn PMReservedEntryVector+3*1Dh ; int 1Dh
|
|
FltRtn PMReservedEntryVector+3*1Eh ; int 1Eh
|
|
FltRtn PMReservedEntryVector+3*1Fh ; int 1Fh
|
|
ELSE
|
|
FltRtn PMReservedEntryVector+5*0h ; int 0
|
|
FltRtn PMReservedEntryVector+5*1h ; int 1
|
|
FltRtn PMReservedEntryVector+5*2h ; int 2
|
|
FltRtn PMReservedEntryVector+5*3h ; int 3
|
|
FltRtn PMReservedEntryVector+5*4h ; int 4
|
|
FltRtn PMReservedEntryVector+5*5h ; int 5
|
|
FltRtn TrapInvalidOpcode ; int 6
|
|
FltRtn PMReservedEntryVector+5*7h ; int 7
|
|
FltRtn TrapDoubleFault ; int 8
|
|
FltRtn TrapExtensionOverrun ; int 9
|
|
FltRtn TrapInvalidTSS ; int A
|
|
FltRtn TrapSegmentNotPresent ; int b
|
|
FltRtn TrapStackOverrun ; int c
|
|
FltRtn TrapGP ; int d
|
|
FltRtn TrapPageFault ; int e
|
|
FltRtn PMReservedEntryVector+5*0Fh ; int f
|
|
FltRtn PMReservedEntryVector+5*10h ; int 10h
|
|
FltRtn PMReservedEntryVector+5*11h ; int 11h
|
|
FltRtn PMReservedEntryVector+5*12h ; int 12h
|
|
FltRtn PMReservedEntryVector+5*13h ; int 13h
|
|
FltRtn PMReservedEntryVector+5*14h ; int 14h
|
|
FltRtn PMReservedEntryVector+5*15h ; int 15h
|
|
FltRtn PMReservedEntryVector+5*16h ; int 16h
|
|
FltRtn PMReservedEntryVector+5*17h ; int 17h
|
|
FltRtn PMReservedEntryVector+5*18h ; int 18h
|
|
FltRtn PMReservedEntryVector+5*19h ; int 19h
|
|
FltRtn PMReservedEntryVector+5*1Ah ; int 1ah
|
|
FltRtn PMReservedEntryVector+5*1Bh ; int 1bh
|
|
FltRtn PMReservedEntryVector+5*1Ch ; int 1ch
|
|
FltRtn PMReservedEntryVector+5*1Dh ; int 1Dh
|
|
FltRtn PMReservedEntryVector+5*1Eh ; int 1Eh
|
|
FltRtn PMReservedEntryVector+5*1Fh ; int 1Fh
|
|
ENDIF
|
|
; PMIntelVector is a table of selector:offsets for routines to process
|
|
; protected mode interrupts in the range 0-1fh. These interrupt numbers
|
|
; are in the range which is "reserved by Intel" for processor exceptions,
|
|
; so the exception handler gets first crack at them.
|
|
|
|
public PMIntelVector
|
|
PMIntelVector Label DWORD
|
|
|
|
FltRtn PMIntrEntryVector+3*0h ; Int 0
|
|
FltRtn PMIntrIgnore ; int 1
|
|
FltRtn PMIntrEntryVector+3*2h ; Int 2
|
|
FltRtn PMIntrIgnore ; int 3
|
|
FltRtn PMIntrEntryVector+3*4h ; Int 4
|
|
FltRtn PMIntrEntryVector+3*5h ; Int 5
|
|
FltRtn PMIntrEntryVector+3*6h ; Int 6
|
|
FltRtn PMIntrEntryVector+3*7h ; Int 7
|
|
FltRtn WowHwIntrEntryVector+8*0h ; Int 8
|
|
FltRtn WowHwIntrEntryVector+8*1h ; Int 9
|
|
FltRtn WowHwIntrEntryVector+8*2h ; Int 0ah
|
|
FltRtn WowHwIntrEntryVector+8*3h ; Int 0bh
|
|
FltRtn WowHwIntrEntryVector+8*4h ; Int 0ch
|
|
FltRtn WowHwIntrEntryVector+8*5h ; Int 0dh
|
|
FltRtn WowHwIntrEntryVector+8*6h ; Int 0eh
|
|
FltRtn WowHwIntrEntryVector+8*7h ; Int 0fh
|
|
FltRtn PMIntrVideo ; int 10h
|
|
FltRtn PMIntrEntryVector+3*11h ; Int 11h
|
|
FltRtn PMIntrEntryVector+3*12h ; Int 12h
|
|
FltRtn PMIntr13 ; int 13h
|
|
FltRtn PMIntrEntryVector+3*14h ; Int 14h
|
|
FltRtn PMIntrMisc ; int 15h
|
|
FltRtn PMIntrEntryVector+3*16h ; Int 16h
|
|
FltRtn PMIntrEntryVector+3*17h ; Int 17h
|
|
FltRtn PMIntrEntryVector+3*18h ; Int 18h
|
|
FltRtn PMIntr19 ; Int 19h
|
|
FltRtn PMIntrEntryVector+3*1ah ; Int 1ah
|
|
FltRtn PMIntrEntryVector+3*1bh ; Int 1bh
|
|
FltRtn PMIntrEntryVector+3*1ch ; Int 1ch
|
|
FltRtn PMIntrEntryVector+3*1dh ; Int 1dh
|
|
FltRtn PMIntrEntryVector+3*1eh ; Int 1eh
|
|
FltRtn PMIntrEntryVector+3*1fh ; Int 1fh
|
|
|
|
ifdef OVERLAY_SUPPORT ;-----------------------------------------------
|
|
|
|
offDestination dw ?
|
|
selDestination dw ?
|
|
|
|
endif ;---------------------------------------------------------------
|
|
|
|
|
|
; if DEBUG ;------------------------------------------------------------
|
|
; For MIPS we need to see where we are faulting - remove for final release
|
|
; LATER
|
|
|
|
; extrn fA20:BYTE
|
|
; extrn fTraceFault:WORD
|
|
|
|
public PMIntNo
|
|
PMIntNo dw 0
|
|
|
|
szRegDump db 'AX=#### BX=#### CX=#### DX=#### SI=#### DI=#### BP=####',0dh,0ah
|
|
db 'DS=#### ES=#### EC=#### CS=#### IP=#### SS=#### SP=####',0dh,0ah
|
|
db '$'
|
|
|
|
; endif ;DEBUG --------------------------------------------------------
|
|
|
|
extrn rgwStack:word
|
|
extrn npEHStackLimit:word
|
|
extrn npEHStacklet:word
|
|
extrn selEHStack:word
|
|
IFDEF WOW
|
|
public WowTransitionToUserMode, WowCopyEhStack,WowCopyIretStack
|
|
public WowReservedReflector,Wow16BitHandlers
|
|
WowTransitionToUserMode dw offset DXPMCODE:Wow16TransitionToUserMode
|
|
WowCopyEhStack dw offset DXPMCODE:Wow16CopyEhStack
|
|
WowCopyIretStack dw offset DXPMCODE:Wow16CopyIretStack
|
|
Wow16BitHandlers dw 256 dup (0,0)
|
|
ENDIF
|
|
|
|
public HwIntHandlers
|
|
HwIntHandlers dd 16 dup (0,0)
|
|
|
|
DXDATA ends
|
|
|
|
|
|
DXSTACK segment
|
|
|
|
public rgw0Stack, rgw2FStack
|
|
|
|
dw 64 dup (?) ; INT 2Fh handler stack
|
|
|
|
rgw2FStack label word
|
|
|
|
dw 64 dup (?) ; DOSX Ring -> Ring 0 transition stack
|
|
;
|
|
; Interrupts in the range 0-1fh cause a ring transition and leave
|
|
; an outer ring IRET frame right here.
|
|
;
|
|
Ring0_EH_DS dw ? ; place to put user DS
|
|
Ring0_EH_AX dw ? ; place to put user AX
|
|
Ring0_EH_BX dw ? ; place to put user BX
|
|
Ring0_EH_CX dw ? ; place to put user CX
|
|
Ring0_EH_BP dw ? ; place to put user BP
|
|
Ring0_EH_PEC dw ? ; lsw of error code for 386 page fault
|
|
; also near return to PMFaultEntryVector
|
|
Ring0_EH_EC dw ? ; error code passed to EH
|
|
Ring0_EH_IP dw ? ; interrupted code IP
|
|
ifdef WOW
|
|
Ring0_EH_EIP dw ? ; high half eip
|
|
endif
|
|
Ring0_EH_CS dw ? ; interrupted code CS
|
|
ifdef WOW
|
|
dw ? ; high half of cs
|
|
endif
|
|
Ring0_EH_Flags dw ? ; interrupted code flags
|
|
ifdef WOW
|
|
Ring0_EH_EFlags dw ? ; high half of flags
|
|
endif
|
|
Ring0_EH_SP dw ? ; interrupted code SP
|
|
ifdef WOW
|
|
Rin0_EH_ESP dw ? ; high half of esp
|
|
endif
|
|
Ring0_EH_SS dw ? ; interrupted code SS
|
|
ifdef WOW
|
|
dw ? ; high half of ss
|
|
endif
|
|
rgw0Stack label word
|
|
|
|
ifdef WOW
|
|
dw 64 dup (?) ; wow stack for initial int field
|
|
public rgwWowStack
|
|
rgwWowStack label word
|
|
endif
|
|
|
|
DXSTACK ends
|
|
|
|
; -------------------------------------------------------
|
|
; CODE SEGMENT VARIABLES
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE segment
|
|
|
|
IFNDEF ROM
|
|
extrn selDgroup:WORD
|
|
ENDIF
|
|
|
|
DXCODE ends
|
|
|
|
DXPMCODE segment
|
|
|
|
public WowHwIntDispatchProc
|
|
WowHwIntDispatchProc dw offset DXPMCODE:Wow16HwIntrReflector
|
|
|
|
extrn selDgroupPM:WORD
|
|
extrn segDXCodePM:WORD
|
|
extrn szFaultMessage:BYTE
|
|
extrn szRing0FaultMessage:BYTE
|
|
extrn RZCall:NEAR
|
|
|
|
IFNDEF ROM
|
|
extrn segDXDataPM:WORD
|
|
ENDIF
|
|
|
|
;
|
|
; The following is a code segment variable, because we need to call
|
|
; through it at a time when none of the other segment register contents
|
|
; can be determined.
|
|
;
|
|
IFDEF WOW
|
|
WowReservedReflector dw offset DXPMCODE:PMReservedReflector
|
|
ENDIF
|
|
|
|
DXPMCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
page
|
|
subttl Protected Mode Interrupt Reflector
|
|
; -------------------------------------------------------
|
|
; PROTECTED MODE INTERRUPT REFLECTOR
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE segment
|
|
assume cs:DXPMCODE
|
|
; -------------------------------------------------------
|
|
; PMIntrEntryVector -- This table contains a vector of
|
|
; near jump instructions to the protected mode interrupt
|
|
; reflector. The protected mode interrupt descriptor
|
|
; table is initialized so that all interrupts jump to
|
|
; locations in this table, which transfers control to
|
|
; the interrupt reflection code for reflecting the
|
|
; interrupt to real mode.
|
|
|
|
public PMIntrEntryVector
|
|
|
|
PMIntrEntryVector:
|
|
|
|
rept 256
|
|
call PMIntrReflector
|
|
endm
|
|
|
|
|
|
public PMFaultEntryVector
|
|
|
|
; -------------------------------------------------------
|
|
; PMFaultEntryVector -- This table contains a vector of
|
|
; near jump instructions to the protected mode fault
|
|
; analyzer.
|
|
;
|
|
PMFaultEntryVector:
|
|
|
|
rept 32
|
|
call PMFaultAnalyzer
|
|
endm
|
|
|
|
assume ds:nothing,es:nothing,ss:nothing
|
|
public PMReservedEntryVector
|
|
PMReservedEntryVector:
|
|
rept 32
|
|
ifdef WOW
|
|
call [WowReservedReflector]
|
|
ELSE
|
|
call PMReservedReflector
|
|
ENDIF
|
|
endm
|
|
|
|
; ------------------------------------------------------------------
|
|
; PMFaultAnalyzer -- This routine is the entry point for
|
|
; the protected mode fault/trap/exception handler. It tries
|
|
; to distinguish between bona fide processor faults and
|
|
; hardware/software interrupts which use the range of
|
|
; interrupts that is reserved by Intel. If a fault is
|
|
; detected, then format the stack for a DPMI fault handler,
|
|
; then vector to the handler whose address is stored in
|
|
; PMFaultVector. If it looks more like an interrupt, then
|
|
; set up the stack for an interrupt handler, jump to the
|
|
; handler whose address is stored in PMIntelVector.
|
|
;
|
|
; Input: none
|
|
; Output: none
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:DGROUP
|
|
public PMFaultAnalyzer
|
|
|
|
PMFaultAnalyzer proc near
|
|
|
|
;
|
|
; Make sure we are on the right stack. Else, something fishy is going on.
|
|
; Note that stack faults won't do too well here.
|
|
;
|
|
push ax
|
|
mov ax,ss
|
|
ifndef WOW
|
|
cmp ax,SEL_DXDATA0
|
|
else
|
|
cmp ax,SEL_DXDATA or STD_RING
|
|
endif
|
|
pop ax
|
|
je pmfa_stack_passed
|
|
jmp pmfa_bad_stack
|
|
pmfa_stack_passed:
|
|
;
|
|
; Is the stack pointer pointing at a word error code (minus 2)?
|
|
;
|
|
ifndef WOW
|
|
cmp sp,offset DGROUP:Ring0_EH_PEC
|
|
else
|
|
cmp sp,offset DGROUP:Ring0_EH_BP ; wow will always have 32bit
|
|
; error code, and NO page fault
|
|
endif
|
|
je pmfa_fault ; Yes, processor fault.
|
|
|
|
;
|
|
; Is the stack pointer pointing at a DWORD error code?
|
|
;
|
|
jc pmfa_pfault ; Yes, page fault.
|
|
; No, fault without EC or interrupt.
|
|
;
|
|
; Is it pointing to where it is supposed to be for a hardware or
|
|
; software interrupt?
|
|
;
|
|
cmp sp,offset DGROUP:Ring0_EH_EC
|
|
je pmfa_20
|
|
jmp pmfa_bad_stack
|
|
pmfa_20:jmp pmfa_inspect
|
|
pmfa_pfault:
|
|
;
|
|
; Is the stack pointer pointing to the right place for a page fault?
|
|
;
|
|
cmp sp,offset DGROUP:Ring0_EH_BP
|
|
je pmfa_pfaultOK ; Yes, it's a page fault
|
|
jmp pmfa_bad_stack
|
|
pmfa_pfaultOK:
|
|
;
|
|
; Error code is a dword, but only a few bits in the lsw are significant
|
|
; on the 80386 and 80486.
|
|
; Put the lsw in the place where the msw was, then fix up the stack
|
|
; pointer to agree with the word EC case, by popping the return into
|
|
; the lsw!
|
|
;
|
|
push Ring0_EH_PEC
|
|
pop Ring0_EH_EC
|
|
pop Ring0_EH_PEC
|
|
pmfa_fault:
|
|
;
|
|
; Getting here, we have a known exception with a word error code of some
|
|
; sort on the stack. Perform an outward ring transition, switch to the
|
|
; client stack, then vector through the exception handler vector to the
|
|
; appropriate handler.
|
|
;
|
|
push bp
|
|
push cx
|
|
push bx
|
|
push ax
|
|
push ds
|
|
lea bp,Ring0_EH_SS
|
|
mov ax,word ptr [bp]
|
|
mov cx,selEHStack
|
|
mov ds,cx
|
|
;Get the Next available EH stacklet
|
|
mov bx, npEHStacklet
|
|
|
|
|
|
if DBG
|
|
cmp bx, CB_STKFRAME ; do we have any stacklets left ?
|
|
jb pmfa_stkerr
|
|
cmp word ptr [bx],0DEADh ; Did app overflow last stacklet ?
|
|
jne pmfa_stkerr
|
|
endif
|
|
; mark next stacklet
|
|
sub bx, CB_STKFRAME
|
|
mov word ptr [bx],0DEADh
|
|
mov npEHStacklet, bx
|
|
add bx, CB_STKFRAME
|
|
|
|
if DBG
|
|
jmp pmfa_copy_stack
|
|
pmfa_stkerr:
|
|
BOP BOP_DBGBREAKPOINT
|
|
jmp pmfa_copy_stack
|
|
db 'dosx:pmfa_stkerr' ; string to search for
|
|
endif
|
|
|
|
pmfa_copy_stack: ; DS:BX = user SS:SP
|
|
|
|
|
|
ifndef WOW
|
|
mov cx,7
|
|
pmfa_copy_stack_loop:
|
|
dec bx
|
|
dec bx
|
|
mov ax,word ptr [bp]
|
|
mov word ptr [bx],ax
|
|
dec bp
|
|
dec bp
|
|
loop pmfa_copy_stack_loop
|
|
|
|
; DS:BX points to stack on entry to PMFaultReflector
|
|
|
|
lea bp,Ring0_EH_PEC
|
|
mov word ptr [bp+6],ds
|
|
mov word ptr [bp+4],bx
|
|
mov word ptr [bp+2],SEL_DXPMCODE or STD_RING
|
|
mov word ptr [bp],offset DXPMCODE:PMFaultReflector
|
|
pop ds
|
|
pop ax
|
|
pop bx
|
|
pop cx
|
|
pop bp
|
|
retf
|
|
|
|
else
|
|
;
|
|
; Build the necessary frames on the user and dosx stack to
|
|
; "switch" to usermode, and dispatch an exception.
|
|
;
|
|
|
|
call [WowCopyEhStack]
|
|
|
|
; N.B. There are now some extra words on our stack. If you
|
|
; pushed something before calling [WowCopyEhStack], you
|
|
; won't find it by poping.
|
|
|
|
;
|
|
; switch to user stack, and return
|
|
;
|
|
jmp [WowTransitionToUserMode]
|
|
endif
|
|
|
|
|
|
pmfa_inspect:
|
|
;
|
|
; Stack is set up as for an interrupt or exception without error code.
|
|
; Adjust the stack pointer and put an error code of zero. Then try to
|
|
; determine whether we have an exception or an interrupt. First test
|
|
; is the interrupt number.
|
|
;
|
|
push Ring0_EH_EC
|
|
mov Ring0_EH_EC,0
|
|
cmp Ring0_EH_PEC,offset PMFaultEntryVector + ((7 + 1) * 3)
|
|
ja pfma_50
|
|
IFDEF WOW
|
|
;
|
|
; build dword error code for fault dispatch
|
|
;
|
|
push Ring0_EH_PEC
|
|
mov Ring0_EH_PEC,0
|
|
ENDIF
|
|
jmp pmfa_fault ; Yes, definitely a fault.
|
|
pfma_50:
|
|
;
|
|
; At this point, all valid exceptions have been eliminated except for
|
|
; exception 9, coprocessor segment overrun, and exception 16, coprocessor
|
|
; error.
|
|
;
|
|
|
|
; **********************************************
|
|
; * Your code to detect these exceptions here. *
|
|
; **********************************************
|
|
|
|
push bp
|
|
push cx
|
|
push bx
|
|
push ax
|
|
push ds ; SP -> Ring0_EH_DS
|
|
;
|
|
; Point to the user's stack.
|
|
;
|
|
ifndef WOW
|
|
lea bp,Ring0_EH_SS
|
|
mov cx,[bp]
|
|
mov ds,cx
|
|
mov bx,[bp-2] ; DS:[BX] -> user stack
|
|
;
|
|
; Copy the IRET frame to the user stack.
|
|
;
|
|
lea bp,Ring0_EH_Flags
|
|
mov cx,3d
|
|
pmfa_copy_IRET:
|
|
mov ax,[bp]
|
|
dec bx
|
|
dec bx
|
|
mov [bx],ax
|
|
dec bp
|
|
dec bp
|
|
loop pmfa_copy_IRET
|
|
;
|
|
; Point BP at vector entry for this (reserved) interrupt.
|
|
;
|
|
mov ax,Ring0_EH_PEC ; fetch near return address
|
|
sub ax,offset DXPMCODE:PMFaultEntryVector+3
|
|
mov cl,3
|
|
div cl ; AX = interrupt number
|
|
shl ax,2 ; AX = vector entry offset
|
|
lea bp,PMIntelVector
|
|
add bp,ax ; BP -> interrupt handler address
|
|
mov ax,[bp] ; AX = IP of handler
|
|
mov cx,[bp+2] ; CX = CS of handler
|
|
;
|
|
; Build the far ret frame for the outward ring transition.
|
|
;
|
|
lea bp,Ring0_EH_PEC
|
|
mov [bp],ax
|
|
mov [bp+2],cx
|
|
mov [bp+4],bx
|
|
mov ax,ds
|
|
mov [bp+6],ax
|
|
|
|
pop ds ; Pop 'em.
|
|
pop ax
|
|
pop bx
|
|
pop cx
|
|
pop bp
|
|
retf ; Out of here.
|
|
else
|
|
call [WowCopyIretStack]
|
|
;
|
|
; Build a far return frame on user stack, switch to user stack, and return
|
|
;
|
|
jmp [WowTransitionToUserMode]
|
|
endif
|
|
|
|
pmfa_bad_stack:
|
|
|
|
if DEBUG
|
|
mov ax,ss
|
|
mov bx,sp
|
|
Trace_Out "Fault Handler Aborting with SS:SP = #AX:#BX"
|
|
pop ax
|
|
sub ax, (offset DXPMCODE:PMFaultEntryVector) + 3
|
|
mov bx,3
|
|
div bl
|
|
Trace_Out "Fault Number #AX"
|
|
pop ax
|
|
pop bx
|
|
pop cx
|
|
pop dx
|
|
Trace_Out "First four stack words: #AX #BX #CX #DX."
|
|
endif
|
|
push selDgroupPM
|
|
push offset DGROUP:rgwStack
|
|
rpushf
|
|
push SEL_DXPMCODE or STD_RING
|
|
push offset DXPMCODE:pmfr_death
|
|
riret
|
|
pmfr_death:
|
|
mov ax,cs
|
|
mov ds,ax
|
|
mov dx,offset szRing0FaultMessage
|
|
pmdossvc 09h
|
|
jmp PMAbort
|
|
|
|
PMFaultAnalyzer endp
|
|
|
|
;
|
|
; This is the format of the stack frame used by the Protected Mode
|
|
; fault reflector and by the reserved interrupt reflector. The
|
|
; three fields in the middle have different meanings, depending on
|
|
; whether we are handling a fault or passing it off to an interrupt
|
|
; handler.
|
|
;
|
|
|
|
FR_Stack Struc
|
|
FR_BP dw ?
|
|
FR_AX dw ?
|
|
FR_BX dw ?
|
|
FR_DS dw ?
|
|
FR_ENTRY dw ? ; SS:[SP] points here on entry
|
|
; to PMReservedReflector
|
|
FR_Toss dw ? ; DPMI return IP
|
|
FR_Ret_IP dw ? ; actual fault handler gets put
|
|
FR_Ret_CS dw ? ; here to return to
|
|
FR_IP dw ?
|
|
FR_CS dw ?
|
|
FR_FL dw ?
|
|
FR_SP dw ?
|
|
FR_SS dw ?
|
|
FR_Stack Ends
|
|
;
|
|
; Alternate names so the structure above makes more sense to
|
|
; PMFaultReflector.
|
|
;
|
|
FR_Handler_IP equ FR_DS
|
|
FR_Handler_CS equ FR_ENTRY
|
|
FR_Handler_Ret_IP equ FR_Toss
|
|
FR_Handler_Ret_CS equ FR_Ret_IP
|
|
FR_Handler_Entry equ FR_Handler_Ret_CS
|
|
FR_EC equ FR_Ret_CS
|
|
|
|
;
|
|
; Stack as seen by a fault handler on entry.
|
|
;
|
|
|
|
EH_Stack Struc
|
|
EH_Ret_IP dw ? ; DPMI fault handler dispatcher
|
|
EH_Ret_CS dw ? ; return address
|
|
EH_EC dw ? ; fault error code
|
|
EH_IP dw ?
|
|
EH_CS dw ?
|
|
EH_FL dw ?
|
|
EH_SP dw ?
|
|
EH_SS dw ?
|
|
EH_Stack Ends
|
|
|
|
; ------------------------------------------------------------------
|
|
; PMFaultReflector -- Dispatch a fault to a fault handler installed
|
|
; in PMFaultVector. When the fault handler returns, return
|
|
; to the faulting code, using the addresses placed on the
|
|
; DPMI fault handler stack by the last called fault handler.
|
|
;
|
|
; Input:
|
|
; Entry is by a NEAR call, with an IP within the range
|
|
; of PMFaultEntryVector on the stack. The stack has been
|
|
; set up for use by a DPMI fault handler.
|
|
;
|
|
; Output:
|
|
; Controlled by fault handler.
|
|
;
|
|
; Uses:
|
|
; Controlled by fault handler.
|
|
;
|
|
; Notes:
|
|
; Fault handlers are called on a static stack. This routine
|
|
; is NOT REENTRANT.
|
|
;
|
|
public PMFaultReflector
|
|
public PMFaultReflectorIRET
|
|
PMFaultReflector proc near
|
|
assume ss:nothing,ds:nothing,es:nothing
|
|
|
|
sub sp,6
|
|
push bx
|
|
push ax
|
|
push bp
|
|
mov bp,sp
|
|
push ds
|
|
mov ax,SEL_DXDATA or STD_RING
|
|
mov ds,ax
|
|
assume ds:dgroup
|
|
mov ax,[bp.FR_Handler_Entry]
|
|
sub ax,offset DXPMCODE:PMFaultEntryVector+3
|
|
mov bl,3
|
|
div bl ; AX = interrupt number
|
|
IFNDEF WOW
|
|
shl ax,2 ; AX = offset of fault handler
|
|
ELSE
|
|
shl ax,3 ; AX = offset of fault handler
|
|
ENDIF
|
|
lea bx,PMFaultVector
|
|
add bx,ax ; SS:[BX] -> fault vector entry
|
|
mov ax,word ptr ds:[bx]
|
|
mov [bp.FR_Handler_IP],ax
|
|
IFNDEF WOW
|
|
mov ax,word ptr ds:[bx+2]
|
|
ELSE
|
|
mov ax,word ptr ds:[bx+4]
|
|
ENDIF
|
|
mov [bp.FR_Handler_CS],ax
|
|
|
|
lea ax,pmfr_cleanup
|
|
mov [bp.FR_Handler_Ret_IP],ax
|
|
push cs
|
|
pop [bp.FR_Handler_Ret_CS]
|
|
|
|
pop ds
|
|
assume ds:nothing
|
|
pop bp
|
|
pop ax
|
|
pop bx
|
|
retf ; This calls the fault handler.
|
|
|
|
PMFaultReflectorIRETCall:
|
|
dd (SEL_RZIRET or STD_RING) shl 10h
|
|
|
|
pmfr_cleanup:
|
|
;
|
|
; Unwind the fault handler stack. Return to the faulting code.
|
|
; This works by calling a Ring 0 procedure to do the actual IRET.
|
|
; If we do it that way, we can return to the faulting code without
|
|
; actually touching the faulting code's stack.
|
|
;
|
|
ifndef WOW
|
|
add sp,2 ; pop off error code
|
|
cli ; can't take interrupts at ring 0
|
|
call dword ptr [PMFaultReflectorIRETCall]
|
|
PMFaultReflectorIRET:
|
|
add sp,4 ; pop off call frame
|
|
|
|
push ax ; Free EH stacklet
|
|
push ds
|
|
mov ax,SEL_DXDATA0
|
|
mov ds, ax
|
|
add ds:npEHStacklet,CB_STKFRAME
|
|
pop ds
|
|
pop ax
|
|
|
|
iret
|
|
else
|
|
PMFaultReflectorIRET:
|
|
;;; if DBG
|
|
BOP BOP_DBGBREAKPOINT ; x86 should never get here
|
|
jmp PMFaultReflectorIret
|
|
db 'PMFaultReflectorIret-X86!'
|
|
;;; endif
|
|
endif
|
|
|
|
|
|
PMFaultReflector endp
|
|
;
|
|
; -------------------------------------------------------
|
|
; PMReservedReflector -- This routine is for reflecting
|
|
; exceptions to a protected mode interrupt handler.
|
|
; The default for exceptions 1, 2, and 3 is to have
|
|
; a near call to this routine placed in the PMFaultVector.
|
|
;
|
|
; This routine strips off the fault handler stack set
|
|
; up by PMFaultAnalyzer, switches to the stack pointed
|
|
; to by the pushed SS and SP values, sets up an IRET
|
|
; frame for use by PMIntrReflector, and jumps to
|
|
; PMIntrReflector. Eventual return is via an IRET
|
|
; from PMIntrReflector.
|
|
;
|
|
; Input:
|
|
; Entry is by a NEAR call, with an IP within the range
|
|
; of PMReservedEntryVector on the stack. The stack has been
|
|
; set up for use by a DPMI fault handler.
|
|
;
|
|
; Output:
|
|
; Switch to stack registers set up by any previous fault
|
|
; handler, jump to PMIntrReflector with an IRET frame set up
|
|
; for direct return to the interrupted code.
|
|
;
|
|
; Errors: none
|
|
;
|
|
; Uses: Modifies SS, SP. Does not return to caller.
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public PMReservedReflector
|
|
PMReservedReflector:
|
|
|
|
push ds
|
|
push bx
|
|
push ax
|
|
push bp
|
|
mov bp,sp
|
|
;
|
|
; BP now points to a stack frame described by the structure
|
|
; above. This will be copied to a stack frame on the stack pointed to
|
|
; by FR_SS:FR_SS. In most cases, the destination stack is actually
|
|
; the same as the present stack, offset by four bytes. The following
|
|
; block of code is therefore very likely an overlapping copy. Think
|
|
; carefully before modifying how it works.
|
|
;
|
|
|
|
mov bx,[bp.FR_SS]
|
|
mov ds,bx
|
|
mov bx,[bp.FR_SP] ; DS:[BX] -> interrupted code's stack
|
|
sub bx, (size FR_Stack) - 4 ; (not copying SP or SS)
|
|
; DS:[BX] -> place to copy our stack frame
|
|
|
|
mov ax,[bp.FR_FL] ; Push user IRET frame onto the destination
|
|
mov [bx.FR_FL],ax ; stack.
|
|
mov ax,[bp.FR_CS]
|
|
mov [bx.FR_CS],ax
|
|
mov ax,[bp.FR_IP]
|
|
mov [bx.FR_IP],ax
|
|
|
|
mov ax,[bp.FR_ENTRY] ; Copy our caller's near return.
|
|
mov [bx.FR_ENTRY],ax
|
|
|
|
mov ax,[bp.FR_DS] ; Copy saved registers.
|
|
mov [bx.FR_DS],ax
|
|
mov ax,[bp.FR_BX]
|
|
mov [bx.FR_BX],ax
|
|
mov ax,[bp.FR_AX]
|
|
mov [bx.FR_AX],ax
|
|
mov ax,[bp.FR_BP]
|
|
mov [bx.FR_BP],ax
|
|
|
|
mov ax,ds ; Switch to user stack.
|
|
mov ss,ax
|
|
mov sp,bx
|
|
mov bp,sp
|
|
|
|
;
|
|
; Deallocate exception stack frame
|
|
;
|
|
push ds
|
|
mov ax,SEL_DXDATA OR STD_RING
|
|
mov ds,ax
|
|
assume ds:DGROUP
|
|
add npEHStacklet,CB_STKFRAME
|
|
pop ds
|
|
assume ds:nothing
|
|
mov ax,[bp.FR_ENTRY] ; AX = offset of caller
|
|
IFNDEF WOW
|
|
sub ax,offset DXPMCODE:PMReservedEntryVector + 3
|
|
mov bl,3
|
|
div bl ; AX = interrupt number
|
|
shl ax,2 ; AX = offset into PMIntelVector
|
|
ELSE
|
|
sub ax,offset DXPMCODE:PMReservedEntryVector + 5
|
|
mov bl,5
|
|
div bl ; AX = interrupt number
|
|
shl ax,3
|
|
ENDIF
|
|
mov ds,SelDgroupPM
|
|
assume ds:DGROUP
|
|
IFNDEF WOW
|
|
lea bx,PMIntelVector
|
|
add bx,ax ; DS:[BX] -> interrupt handler
|
|
|
|
mov ax,[bx] ; Place vector entry just below
|
|
mov [bp.FR_Ret_IP],ax ; IRET frame.
|
|
mov ax,[bx+2]
|
|
mov [bp.FR_Ret_CS],ax
|
|
ELSE
|
|
push es
|
|
push SEL_IDT OR STD_RING
|
|
pop es
|
|
|
|
mov bx,ax
|
|
mov ax,es:[bx].offDest
|
|
mov [bp.FR_Ret_IP],ax ; IRET frame.
|
|
mov ax,es:[bx].selDest
|
|
mov [bp.FR_Ret_CS],ax
|
|
pop es
|
|
ENDIF
|
|
lea sp,[bp.FR_BP] ; Point to saved registers.
|
|
pop bp ; Pop 'em.
|
|
pop ax
|
|
pop bx
|
|
pop ds
|
|
add sp,4 ; Fix up stack.
|
|
|
|
retf ; jump to interrupt handler via far return
|
|
|
|
;
|
|
; -------------------------------------------------------
|
|
; PMIntrReflector -- This routine is the entry point for
|
|
; the protected mode interrupt reflector. This routine
|
|
; is entered when an interrupt occurs (either software
|
|
; or hardware). It switches the processor to real mode
|
|
; and transfers control to the appropriate interrupt
|
|
; service routine for the interrupt. After the interrupt
|
|
; service routine completes, it switches back to protected
|
|
; mode and returns control to the originally interrupted
|
|
; protected mode code.
|
|
; Entry to this routine comes from the PMIntrEntryVector,
|
|
; which contains a vector of near call instructions, which
|
|
; all call here. The interrupt number is determined from
|
|
; the return address of the near call from the interrupt
|
|
; entry vector.
|
|
; The address of the real mode interrupt service routine to
|
|
; execute is determined from the real mode interrupt vector
|
|
; table and the interrupt number.
|
|
;
|
|
; Input: none
|
|
; Output: none
|
|
; Errors: none
|
|
; Uses: The segment registers are explicitly preserved by
|
|
; this routine. Other registers are as preserved or
|
|
; modified by the interrutp service routine.
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public PMIntrReflector
|
|
|
|
PMIntrReflector:
|
|
;
|
|
; On entry, the stack layout is:
|
|
; [6] FLAGS - "
|
|
; [4] CS - "
|
|
; [2] IP - from original interrupt
|
|
; [0] IP - from interrupt entry vector call
|
|
;
|
|
|
|
FCLI
|
|
cld
|
|
push ds
|
|
mov ds,selDgroupPM
|
|
assume ds:DGROUP
|
|
mov regUserAX,ax ;save user AX for later
|
|
|
|
if DEBUG
|
|
;
|
|
; Are we on a DOSX interrupt reflector stack?
|
|
;
|
|
mov ax,ss
|
|
cmp ax,selDgroupPM
|
|
jne @F
|
|
cmp sp,offset bReflStack
|
|
jb @F
|
|
cmp sp,offset pbReflStack
|
|
jnb @F
|
|
;
|
|
; If so, have we overflowed a stacklet?
|
|
;
|
|
mov ax,pbReflStack
|
|
cmp sp,ax
|
|
ja @F
|
|
add ax,CB_STKFRAME
|
|
cmp sp,ax
|
|
jb @F
|
|
mov ax,regUserAX
|
|
Debug_Out "DOSX:PMIntrReflector--Reflector stack overflow."
|
|
@@:
|
|
endif; DEBUG
|
|
|
|
push bp ;stack -> BP DS IP IP CS FL
|
|
mov bp,sp ; [0] [2] [4] [6] [8] [A]
|
|
mov ax,[bp+0Ah] ;get the interrupted routine's flags
|
|
and ax,NOT 4100h ;clear the trace flag in case we got
|
|
; an interrupt on an instruction about
|
|
; to be single stepped
|
|
mov regUserFL,ax ;and save for later
|
|
mov ax,es
|
|
xchg ax,[bp+4] ;save ES and get entry vector address
|
|
pop bp
|
|
;stack -> DS ES IP CS FL
|
|
; [0] [2] [4] [6] [8]
|
|
|
|
; The state that we want to save on the user's stack has been set up.
|
|
; Convert the entry vector return address into an interrupt number.
|
|
|
|
sub ax,offset PMIntrEntryVector+3
|
|
push cx
|
|
mov cl,3
|
|
div cl
|
|
pop cx
|
|
|
|
;if DEBUG ; debugbug
|
|
mov PMIntNo,ax
|
|
;endif
|
|
DEBUG_TRACE DBGTR_ENTRY, ax, 0, 1000h
|
|
|
|
shl ax,2 ;turn interrupt number into interrupt
|
|
; table offset
|
|
|
|
; Allocate a new stack frame, and then switch to the reflector stack
|
|
; frame.
|
|
mov regUserSP,sp ;save entry stack pointer so we can
|
|
mov regUSerSS,ss ; switch to our own stack
|
|
ASSERT_REFLSTK_OK
|
|
mov ss,selDgroupPM ;switch to the reflector stack frame
|
|
mov sp,pbReflStack
|
|
FIX_STACK
|
|
push pbReflStack ;save stack frame ptr on stack
|
|
sub pbReflStack,CB_STKFRAME ;adjust pointer to next stack frame
|
|
|
|
|
|
if DEBUG ;--------------------------------------------------------
|
|
|
|
push 0ABCDh ;a debugging marker & interrupt value
|
|
push PMIntNo
|
|
|
|
cmp fTraceReflect,0
|
|
jz @f
|
|
push ax
|
|
mov ax,PMIntNo
|
|
Trace_Out "[pr#AL]",x
|
|
pop ax
|
|
@@:
|
|
|
|
; Perform a too-late-to-save-us-now-but-we-want-to-know check on the
|
|
; reflector stack.
|
|
|
|
cmp StackGuard,1022h
|
|
jz @f
|
|
Debug_Out "DOSX:PMIntrReflector--Global reflector stack overflow."
|
|
@@:
|
|
endif ;DEBUG ---------------------------------------------------------
|
|
|
|
; We are now running on our own stack, so we can switch into real mode.
|
|
|
|
push ax ;save interrupt vector table offset
|
|
SwitchToRealMode
|
|
assume es:nothing
|
|
|
|
xor ax,ax
|
|
mov es,ax
|
|
pop ax
|
|
|
|
; Build an IRET frame on the stack so that the real mode interrupt service
|
|
; routine will return to us when it is finished.
|
|
|
|
push regUserSS ;save user stack address on our own stack
|
|
push regUserSP ; frame so we can restore it later
|
|
push ds
|
|
push regUserFL
|
|
push cs
|
|
push offset pmrf50
|
|
|
|
; Build an IRET frame on the stack to use to transfer control to the
|
|
; real mode interrupt routine.
|
|
|
|
xchg bx,ax ;interrupt vector offset to BX, preserve BX
|
|
|
|
and byte ptr regUserFL+1,not 02h ;use entry flags less
|
|
push regUserFL ; the interrupt flag (IF)
|
|
|
|
push ax
|
|
mov ax,word ptr RmHwIsr[bx]
|
|
or ax,word ptr RmHwIsr[bx + 2]
|
|
je pmrf20
|
|
|
|
;
|
|
; Don't reflect to the reflector that will reflect back to pmode
|
|
;
|
|
pop ax
|
|
push word ptr RmHwIsr[bx+2]
|
|
push word ptr RmHwIsr[bx]
|
|
jmp pmrf30
|
|
|
|
pmrf20: pop ax
|
|
push word ptr es:[bx+2] ;push segment of isr
|
|
push word ptr es:[bx] ;push offset of isr
|
|
pmrf30: xchg bx,ax
|
|
mov ax,regUserAX ;restore entry value of AX
|
|
;
|
|
; At this point the interrupt reflector stack looks like this:
|
|
;
|
|
; [18] previous stack frame pointer
|
|
; [16] stack segment of original stack
|
|
; [14] stack pointer of original stack
|
|
; [12] real mode dos extender data segment
|
|
; [10] dos extender flags
|
|
; [8] segment of return address back to interupt reflector
|
|
; [6] offset of return address back to interrupt reflector
|
|
; [4] user flags as on entry from original interrupt
|
|
; [2] segment of real mode ISR
|
|
; [0] offset of real mode ISR
|
|
|
|
; Execute the real mode interrupt service routine
|
|
|
|
iret
|
|
|
|
; The real mode ISR will return here after it is finsished.
|
|
|
|
pmrf50: pop ds
|
|
pushf
|
|
|
|
FCLI ;We have to clear interrupts here, because
|
|
cld ; the interrupt routine may have returned
|
|
; with interrupts on and our code that uses
|
|
; static variables must be protected. We
|
|
; turn them off after to pushf instruction so
|
|
; that we can preserve the state of the
|
|
; interrupt flag as returned by the ISR.
|
|
|
|
mov regUserAX,ax
|
|
pop ax
|
|
pop regUserSP
|
|
pop regUserSS
|
|
|
|
if DEBUG
|
|
add sp,4 ;'pop' off debugging info
|
|
endif
|
|
CHECK_STACK
|
|
ASSERT_REFLSTK_OK
|
|
pop pbReflStack ;deallocate stack frame(s)--it used to be that
|
|
; we'd simply add CB_STKFRAME to pbReflStack
|
|
; to deallocate a frame. But we found a TSR
|
|
; that would pop up on an Int 28h and iret
|
|
; on the Int 28h frame from an Int 8h! This
|
|
; left some stack allocated, and soon resulted
|
|
; in running out of frames. Keeping the frame
|
|
; pointer on the stack allows us to pop
|
|
; multiple frames at once.
|
|
ASSERT_REFLSTK_OK
|
|
|
|
; Switch back to protected mode.
|
|
|
|
push ax ;preserve AX
|
|
SwitchToProtectedMode
|
|
pop ax
|
|
|
|
DEBUG_TRACE DBGTR_EXIT, 0, 0, 1000h
|
|
; Switch back to the original stack.
|
|
|
|
mov ss,regUserSS
|
|
mov sp,regUserSP
|
|
|
|
; Put the flags returned by the real mode interrupt routine back into
|
|
; the caller's stack so that they will be returned properly.
|
|
|
|
push bp ;stack -> BP DS ES IP CS FL
|
|
mov bp,sp ; [0] [2] [4] [6] [8] [10]
|
|
and [bp+10],0300h ;clear all but the interrupt and trace flags
|
|
; in the caller's original flags
|
|
or [bp+10],ax ;combine in the flags returned by the
|
|
; interrupt service routine. This will cause
|
|
; us to return to the original routine with
|
|
; interrupts on if they were on when the
|
|
; interrupt occured, or if the ISR returned
|
|
; with them on.
|
|
pop bp
|
|
|
|
; And return to the original interrupted program.
|
|
|
|
mov ax,regUserAX
|
|
pop ds
|
|
pop es
|
|
riret
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
subttl Real Mode Interrupt Reflector
|
|
page
|
|
; -------------------------------------------------------
|
|
; REAL MODE INTERRUPT REFLECTOR
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE segment
|
|
assume cs:DXCODE
|
|
; -------------------------------------------------------
|
|
; RMIntrEntryVector -- This table contains a vector of
|
|
; near jump instructions to the real mode interrupt
|
|
; reflector. Real mode interrupts that have been hooked
|
|
; by the protected mode application have their vector
|
|
; set to entry the real mode reflector through this table.
|
|
|
|
public RMIntrEntryVector,EndRmIntrEntry
|
|
|
|
RMIntrEntryVector:
|
|
|
|
rept 256
|
|
call RMIntrReflector
|
|
endm
|
|
|
|
EndRMIntrEntry:
|
|
|
|
; -------------------------------------------------------
|
|
; RMIntrReflector -- This routine is the entry point for
|
|
; the real mode interrupt reflector. This routine
|
|
; is entered when an interrupt occurs (either software
|
|
; or hardware) that has been hooked by the protected mode
|
|
; application. It switches the processor to protected mode
|
|
; and transfers control to the appropriate interrupt
|
|
; service routine for the interrupt. After the interrupt
|
|
; service routine completes, it switches back to real
|
|
; mode and returns control to the originally interrupted
|
|
; real mode code.
|
|
; Entry to this routine comes from the RMIntrEntryVector,
|
|
; which contains a vector of near call instructions, which
|
|
; all call here. The interrupt number is determined from
|
|
; the return address of the near call from the interrupt
|
|
; entry vector.
|
|
; The address of the protected mode interrupt service routine
|
|
; to execute is determined from the protected mode interrupt
|
|
; descriptor tabel and the interrupt number.
|
|
;
|
|
; Input: none
|
|
; Output: none
|
|
; Errors: none
|
|
; Uses: The segment registers are explicitly preserved by
|
|
; this routine. Other registers are as preserved or
|
|
; modified by the interrutp service routine.
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public RMIntrReflector
|
|
|
|
RMIntrReflector:
|
|
;
|
|
; On entry, the stack layout is:
|
|
; [6] FLAGS - "
|
|
; [4] CS - "
|
|
; [2] IP - from original interrupt
|
|
; [0] IP - from interrupt entry vector call
|
|
;
|
|
FCLI
|
|
cld
|
|
push ds
|
|
IFDEF ROM
|
|
SetRMDataSeg
|
|
ELSE
|
|
mov ds,selDgroup
|
|
ENDIF
|
|
assume ds:DGROUP
|
|
if DEBUG
|
|
;
|
|
; Are we on a DOSX interrupt reflector stack?
|
|
;
|
|
push ax
|
|
push cx
|
|
mov ax,ss
|
|
mov cx,ds
|
|
cmp ax,cx
|
|
pop cx
|
|
jne @F
|
|
|
|
cmp sp,offset bReflStack
|
|
jb @F
|
|
cmp sp,offset pbReflStack
|
|
jnb @F
|
|
;
|
|
; If so, have we overflowed a stacklet?
|
|
;
|
|
mov ax,pbReflStack
|
|
cmp sp,ax
|
|
ja @F
|
|
add ax,CB_STKFRAME
|
|
cmp sp,ax
|
|
jb @F
|
|
pop ax
|
|
Real_Debug_Out "DOSX:RMIntrReflector--Reflector stack overflow."
|
|
push ax
|
|
@@:
|
|
pop ax
|
|
endif ;DEBUG
|
|
mov regUserAX,ax ;save user AX for later
|
|
push bp ;stack -> BP DS IP IP CS FL
|
|
mov bp,sp ; [0] [2] [4] [6] [8] [A]
|
|
mov ax,[bp+0Ah] ;get the interrupted routine's flags
|
|
and ax,NOT 4100h ;clear the trace flag in case we got
|
|
; an interrupt on an instruction about
|
|
; to be single stepped
|
|
mov regUserFL,ax ;and save for later
|
|
mov ax,es
|
|
xchg ax,[bp+4] ;save ES and get entry vector address
|
|
pop bp
|
|
|
|
; Some software (like older versions of Smartdrv.sys) may enable A20 on
|
|
; their own, and get very 'suprised' to find it turned off by our PM->RM
|
|
; mode switch. If they used Himem.sys, this wouldn't be necessary, but...
|
|
|
|
if VCPI
|
|
cmp fVCPI,0
|
|
jnz @f
|
|
endif
|
|
push ax ;get/save current A20 state on stack
|
|
push bx
|
|
xmssvc 7
|
|
mov regUserSP,ax ;use regUserSP as a temp var
|
|
pop bx
|
|
pop ax
|
|
@@:
|
|
push regUserSP
|
|
|
|
; The state that we want to save on the user's stack has been set up.
|
|
; Convert the entry vector return address into an interrupt number.
|
|
|
|
sub ax,offset RMIntrEntryVector+3
|
|
push cx
|
|
mov cl,3
|
|
div cl
|
|
pop cx
|
|
|
|
;if DEBUG ; debugbug
|
|
mov PMIntNo,ax
|
|
;endif
|
|
|
|
; Allocate a new stack frame, and then switch to the reflector stack
|
|
; frame.
|
|
|
|
mov regUserSP,sp ;save entry stack pointer so we can
|
|
mov regUSerSS,ss ; switch to our own stack
|
|
IFDEF ROM
|
|
push ds
|
|
pop ss
|
|
ELSE
|
|
ASSERT_REFLSTK_OK
|
|
mov ss,selDgroup ;switch to the reflector stack frame
|
|
ENDIF
|
|
mov sp,pbReflStack
|
|
FIX_STACK
|
|
push pbReflStack ;save stack frame ptr on stack
|
|
sub pbReflStack,CB_STKFRAME ;adjust pointer to next stack frame
|
|
|
|
; We are now running on our own stack, so we can switch into protected mode.
|
|
|
|
push ax ;save interrupt vector table offset
|
|
SwitchToProtectedMode
|
|
pop ax
|
|
|
|
if DEBUG ;--------------------------------------------------------
|
|
|
|
push 0DEADh ;debugging id & interrupt number
|
|
push PMIntNo
|
|
|
|
cmp fTraceReflect,0
|
|
jz @f
|
|
push ax
|
|
mov ax,PMIntNo
|
|
Trace_Out "(rp#AL)",x
|
|
pop ax
|
|
@@:
|
|
|
|
; Perform a too-late-to-save-us-now-but-we-want-to-know check on the
|
|
; reflector stack.
|
|
|
|
cmp StackGuard,1022h
|
|
jz @f
|
|
Debug_Out "DOSX:RMIntrReflector--Global reflector stack overflow."
|
|
@@:
|
|
endif ;DEBUG ---------------------------------------------------------
|
|
|
|
; Build an IRET frame on the stack so that the protected mode interrupt service
|
|
; routine will return to us when it is finished.
|
|
|
|
push regUserSS ;save user stack address on our own stack
|
|
push regUserSP ; frame so we can restore it later
|
|
push ds
|
|
IFDEF WOW
|
|
DEBUG_TRACE DBGTR_ENTRY, ax, 0, 0
|
|
|
|
cmp ax, 8
|
|
jb short rmrf_nothw
|
|
cmp ax, 10h
|
|
jb short rmrf_hw
|
|
cmp ax, 70h
|
|
jb short rmrf_nothw
|
|
cmp ax, 78h
|
|
jnb short rmrf_nothw
|
|
|
|
rmrf_hw:
|
|
push es
|
|
push ax
|
|
push bx
|
|
mov ax, SEL_VDMTIB or STD_RING
|
|
mov es, ax
|
|
inc word ptr es:[VDMTIB_LockCount]
|
|
cmp word ptr es:[VDMTIB_LockCount], 1
|
|
jnz short rmrf_nosw
|
|
|
|
mov ax, ss
|
|
mov es:[VDMTIB_SaveSsSelector], ax
|
|
mov ax, sp
|
|
add ax, 6
|
|
mov word ptr es:[VDMTIB_SaveEsp], ax
|
|
mov word ptr es:[VDMTIB_SaveEsp+2], 0
|
|
|
|
mov bx, word ptr es:[VDMTIB_Esp]
|
|
sub bx, 6
|
|
pop ax
|
|
mov ds:[bx], ax ;bx
|
|
pop ax
|
|
mov ds:[bx+2], ax ;ax
|
|
pop ax
|
|
mov ds:[bx+4], ax ;es
|
|
push word ptr es:[VDMTIB_SsSelector]
|
|
pop ss
|
|
mov sp, bx
|
|
|
|
rmrf_nosw:
|
|
pop bx
|
|
pop ax
|
|
pop es
|
|
|
|
test DpmiFlags,DPMI_32BIT
|
|
jnz rmrf_32
|
|
.386p
|
|
push regUserFL
|
|
popf ;BUGBUG perf! this will trap
|
|
pushfd
|
|
sub esp,2
|
|
push cs
|
|
push dword ptr (offset rmrf50)
|
|
.286p
|
|
jmp short rmrf_hwint_cont
|
|
rmrf_nothw:
|
|
|
|
test DpmiFlags,DPMI_32BIT
|
|
jnz rmrf_32
|
|
ENDIF
|
|
push regUserFL
|
|
push cs
|
|
push offset rmrf50
|
|
rmrf_hwint_cont:
|
|
|
|
; Build an IRET frame on the stack to use to transfer control to the
|
|
; protected mode ISR
|
|
|
|
and byte ptr regUserFL+1,not 02h ;use entry flags less the
|
|
push regUserFL ; interrupt flag (IF)
|
|
|
|
xchg bx,ax ;interrupt vector offset to BX, preserve BX
|
|
IFNDEF WOW
|
|
cmp bx,CRESERVED ;Interrupt in reserved range?
|
|
jc rmrf_reserved
|
|
ENDIF
|
|
shl bx,3
|
|
mov es,selIDT
|
|
jmp rmrf_setISR
|
|
rmrf_reserved:
|
|
IFNDEF WOW
|
|
shl bx,2
|
|
mov es,SelDgroupPM
|
|
add bx,offset DGROUP:PMIntelVector
|
|
ENDIF
|
|
rmrf_setISR:
|
|
push word ptr es:[bx+2] ;push segment of isr
|
|
rmrf_setISROff:
|
|
push word ptr es:[bx] ;push offset of isr
|
|
xchg bx,ax
|
|
mov ax,regUserAX ;restore entry value of AX
|
|
push ds
|
|
pop es
|
|
|
|
; At this point the interrupt reflector stack looks like this:
|
|
;
|
|
; [18] previous stack frame pointer
|
|
; [16] stack segment of original stack
|
|
; [14] stack pointer of original stack
|
|
; [12] protected mode dos extender data segment
|
|
; [10] dos extender flags
|
|
; [8] segment of return address back to interupt reflector
|
|
; [6] offset of return address back to interrupt reflector
|
|
; [4] user flags as on entry from original interrupt
|
|
; [2] segment of protected mode ISR
|
|
; [0] offset of protected mode ISR
|
|
;
|
|
; Execute the protected mode interrupt service routine
|
|
|
|
iret
|
|
IFDEF WOW
|
|
.386p
|
|
rmrf_32:
|
|
pushfd
|
|
push ax
|
|
mov ax,regUserFL
|
|
mov word ptr [esp + 2],ax
|
|
pop ax
|
|
sub esp,2
|
|
push cs
|
|
push dword ptr (offset rmrf50)
|
|
|
|
; Build an IRET frame on the stack to use to transfer control to the
|
|
; protected mode ISR
|
|
|
|
and byte ptr regUserFL+1,not 02h ;use entry flags less the
|
|
pushfd
|
|
push ax
|
|
mov ax,regUserFL ; interrupt flag (IF)
|
|
mov word ptr [esp + 2],ax
|
|
pop ax
|
|
|
|
xchg bx,ax ;interrupt vector offset to BX, preserve BX
|
|
shl bx,3
|
|
mov es,selIDT
|
|
rmrf_32setISR:
|
|
; bugbug this is not correct. For vectors above 32, it will
|
|
; grab the segment from the wrong part of the IDT.
|
|
|
|
push 0 ;hiword of segment
|
|
push word ptr es:[bx+2] ;segment
|
|
push word ptr es:[bx+6] ;hiword of offset
|
|
push word ptr es:[bx] ;loword of offset
|
|
|
|
xchg bx,ax
|
|
mov ax,regUserAX ;restore entry value of AX
|
|
push ds
|
|
pop es
|
|
iretd
|
|
.286p
|
|
endif
|
|
|
|
; The protected mode ISR will return here after it is finsished.
|
|
|
|
rmrf50: pop ds
|
|
pushf ;save flags as returned by PM Int routine
|
|
|
|
FCLI ;We have to clear interrupts here, because
|
|
cld ; the interrupt routine may have returned
|
|
; with interrupts on and our code that uses
|
|
; static variables must be protected. We
|
|
; turn them off after to pushf instruction so
|
|
; that we can preserve the state of the
|
|
; interrupt flag as returned by the ISR.
|
|
mov regUserAX,ax
|
|
pop ax
|
|
pop regUserSP
|
|
pop regUserSS
|
|
|
|
if DEBUG
|
|
add sp,4 ;'pop' off debugging info
|
|
endif
|
|
|
|
ASSERT_REFLSTK_OK
|
|
CHECK_STACK
|
|
pop pbReflStack ;deallocate stack frame(s)
|
|
ASSERT_REFLSTK_OK
|
|
|
|
; Switch back to real mode.
|
|
|
|
push ax ;preserve AX
|
|
SwitchToRealMode
|
|
pop ax
|
|
|
|
; Switch back to the original stack.
|
|
|
|
mov ss,regUserSS
|
|
mov sp,regUserSP
|
|
|
|
; Make sure the A20 line matches whatever state it was when the int occured.
|
|
; This is for the benefit of any software that diddles A20 without using
|
|
; an XMS driver
|
|
|
|
pop regUserSP ;A20 state at time of interrupt to temp var
|
|
if VCPI
|
|
cmp fVCPI,0
|
|
jnz rmrf75
|
|
endif
|
|
push ax ;save current ax
|
|
mov ax,regUserSP ;ax = A20 state at time of interrupt
|
|
or ax,ax ;if it was off, don't sweat it
|
|
jz rmrf70
|
|
push bx ;save bx (XMS calls destroy bl)
|
|
push ax
|
|
xmssvc 7 ;ax = current A20 state
|
|
pop bx ;bx = old A20 state
|
|
cmp ax,bx ;if A20 is still on, don't need to diddle
|
|
jz @f
|
|
xmssvc 5 ;force A20 back on
|
|
inc A20EnableCount ; and remember that we did this
|
|
if DEBUG
|
|
or fA20,04h
|
|
endif
|
|
@@:
|
|
pop bx
|
|
rmrf70:
|
|
pop ax
|
|
rmrf75:
|
|
|
|
; Put the flags returned by the real mode interrupt routine back into
|
|
; the caller's stack so that they will be returned properly.
|
|
|
|
push bp ;stack -> BP DS ES IP CS FL
|
|
mov bp,sp ; [0] [2] [4] [6] [8] [10]
|
|
and [bp+10],0300h ;clear all but the interrupt and trace flags
|
|
; in the caller's original flags
|
|
or [bp+10],ax ;combine in the flags returned by the
|
|
; interrupt service routine. This will cause
|
|
; us to return to the original routine with
|
|
; interrupts on if they were on when the
|
|
; interrupt occured, or if the ISR returned
|
|
; with them on.
|
|
pop bp
|
|
|
|
; And return to the original interrupted program.
|
|
|
|
mov ax,regUserAX
|
|
pop ds
|
|
pop es
|
|
iret
|
|
|
|
DXCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
subttl INT 24h Critical Error Mapper
|
|
page
|
|
; -------------------------------------------------------
|
|
; DOS CRITICAL ERROR MAPPER
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE segment
|
|
|
|
; -------------------------------------------------------
|
|
; RMDefaultInt24Handler -- Default action for a DOS critical
|
|
; error is to fail the call.
|
|
;
|
|
public RMDefaultInt24Handler
|
|
RMDefaultInt24Handler proc far
|
|
mov al,3
|
|
iret
|
|
RMDefaultInt24Handler endp
|
|
|
|
DXCODE ends
|
|
|
|
DXCODE segment
|
|
assume cs:DXCODE
|
|
|
|
; -------------------------------------------------------
|
|
; RMIntr24 -- This routine is a real-mode hook that traps
|
|
; DOS critical errors, and maps them to protect mode
|
|
; handlers. To make the critical error realistic to
|
|
; the application, we switch to the applications
|
|
; stack and copy the critical error stack frame to
|
|
; there.
|
|
|
|
; On entry, the stack layout is:
|
|
;
|
|
; [0] [2] [4] [6] [8] [10] [12] [14] [16] [18] [20] [22] [24] [26] [28]
|
|
; IP CS FL AX BX CX DX SI DI BP DS ES IP CS FL
|
|
;
|
|
; |------------| |------------------------------------------| |------------|
|
|
;
|
|
; IRET TO DOS REGS AT TIME OF INT 24H IRET TO APP
|
|
;
|
|
|
|
public RMIntr24
|
|
|
|
RMIntr24 proc far
|
|
|
|
FCLI
|
|
cld
|
|
push es
|
|
push ds
|
|
IFDEF ROM
|
|
SetRMDataSeg
|
|
ELSE
|
|
mov ds,selDgroup ;stack -> DS ES IP CS FL ...
|
|
ENDIF
|
|
assume ds:DGROUP ; [0] [2] [4] [6] [8] ...
|
|
|
|
; We need a temporary stack to do real->protect mode switching, etc.
|
|
; Allocate and use an interrupt frame for that.
|
|
|
|
mov regUserSP,sp ;save entry stack pointer so we can
|
|
mov regUSerSS,ss ; switch to our own stack
|
|
IFDEF ROM
|
|
push ds
|
|
pop ss
|
|
ELSE
|
|
ASSERT_REFLSTK_OK
|
|
mov ss,selDgroup ;switch to the reflector stack frame
|
|
ENDIF
|
|
mov sp,pbReflStack
|
|
sub pbReflStack,CB_STKFRAME ;adjust pointer to next stack frame
|
|
FIX_STACK
|
|
push ax ;save ax, switch to protected mode
|
|
SwitchToProtectedMode ; need to be on our stack
|
|
pop ax
|
|
|
|
; Now switch to the applications stack frame. We assume that the dos function
|
|
; generating the critical error came from a protected mode app and was passed
|
|
; through PMIntrDos, who saved the app's current stack in regusrss:regusrsp.
|
|
|
|
mov ss,pmusrss ;switch (back) to app's stack
|
|
ifndef WOW
|
|
mov sp,pmusrsp
|
|
else
|
|
.386p
|
|
movzx esp,word ptr pmusrsp
|
|
.286p
|
|
endif
|
|
|
|
push regUserSS ;save prior stack address on app's stack
|
|
push regUserSP ; frame so we can restore it later
|
|
|
|
; Copy critical error stack info to application's stack
|
|
|
|
pushf ;we don't really know where the original
|
|
push cs ; int 21h service was requested, so fake
|
|
push offset rm24trap ; one to point at a routine of ours
|
|
|
|
sub sp,9*2 ;temp save the general regs further down the
|
|
pusha ; stack, they'll get poped in a little while
|
|
|
|
mov ax,regUserSS ;we need a selector to the previous stack
|
|
mov bx,STD_DATA ;(it is almost certainly the PMIntrDos
|
|
call ParaToLDTSelector ; real mode stack, but this is playing safe)
|
|
|
|
mov cx,9 ;okay, now copy the 9 register values from
|
|
mov si,regUserSP ; the DOS visable stack to the app's
|
|
add si,5*2
|
|
mov ds,ax
|
|
assume ds:NOTHING
|
|
push ss
|
|
pop es
|
|
mov di,sp
|
|
add di,8*2
|
|
cld
|
|
rep movsw
|
|
|
|
mov ds,selDgroupPM ;restore addressability to our DGROUP
|
|
assume ds:DGROUP
|
|
|
|
; On entry, BP:SI points to a device header. Map BP from a seg to a selector.
|
|
|
|
mov ax,bp
|
|
mov bx,STD_DATA
|
|
call ParaToLDTSelector
|
|
mov regUserAX,ax
|
|
|
|
popa ;restore initial register values
|
|
|
|
mov bp,regUserAX ;give them the selector, not the segment
|
|
|
|
; Invoke the protected mode handler
|
|
|
|
ifdef WOW
|
|
.386p
|
|
test DpmiFlags,word ptr DPMI_32BIT
|
|
jz ri2410
|
|
|
|
pushfd
|
|
push 0
|
|
push cs
|
|
push 0
|
|
push offset rm24ret
|
|
jmp ri2420
|
|
.286p
|
|
endif
|
|
ri2410: pushf ;put our return address on the stack so the
|
|
push cs ; handler will return to us when it's done.
|
|
push offset rm24ret
|
|
|
|
ifndef WOW
|
|
pushf ;transfer control to the
|
|
push word ptr PMInt24Handler+2 ; pm handler
|
|
push word ptr PMInt24Handler
|
|
iret
|
|
else
|
|
.386p
|
|
ri2420: pushfd ;transfer control to the
|
|
push dword ptr PMInt24Handler+4 ; pm handler
|
|
push dword ptr PMInt24Handler
|
|
iretd
|
|
.286p
|
|
endif
|
|
|
|
; The protected mode critical error handler returns here when it's finished
|
|
; (at least it had better return here!)
|
|
|
|
public rm24ret
|
|
rm24ret:
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
FCLI
|
|
cld
|
|
|
|
add sp,12*2 ;clear critical error junk from stack
|
|
|
|
rm24exit:
|
|
mov ds,selDgroupPM ;DOS extender data segment
|
|
assume ds:DGROUP
|
|
|
|
mov regUserAX,ax ;save action code from pm handler
|
|
pop regUserSP ;pop prior stack location
|
|
pop regUserSS
|
|
|
|
; Switch back to the temp interrupt stack frame, drop to real mode, back
|
|
; to the initial stack, and return to DOS.
|
|
|
|
ASSERT_REFLSTK_OK
|
|
CHECK_STACK
|
|
add pbReflStack,CB_STKFRAME ;in the reverse order from above so
|
|
ASSERT_REFLSTK_OK
|
|
mov ss,selDgroupPM ; that we wind up in the same place
|
|
ifndef WOW
|
|
mov sp,pbReflStack
|
|
else
|
|
.386p
|
|
movzx esp,pbReflStack
|
|
.286p
|
|
endif
|
|
|
|
|
|
SwitchToRealMode ;gotta be on our own stack to do this
|
|
|
|
mov ax,regUserAX ;recover AX from pm critical error handler
|
|
|
|
mov ss,regUserSS ;switch back to the original stack.
|
|
mov sp,regUserSP
|
|
|
|
pop ds ;return to DOS
|
|
pop es
|
|
iret
|
|
|
|
; -------------------------------------------------------
|
|
;
|
|
; rm24trap -- This code gets executed if the protected mode critical
|
|
; error handler attempts to bypass DOS and return directly
|
|
; to the application. Currently this is not allowed, and
|
|
; we just return to DOS anyway--most likely to die!
|
|
;
|
|
; Note: THIS IS NOT SUPPORTED! DON'T DO THIS!
|
|
|
|
BeginHighSegment
|
|
|
|
public rm24trap
|
|
|
|
rm24trap:
|
|
|
|
Debug_Out "Critical error handler tried to return to application!"
|
|
|
|
jmp short rm24exit
|
|
|
|
EndHighSegment
|
|
|
|
RMIntr24 endp
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
subttl INT 28h Idle Handler
|
|
page
|
|
; -------------------------------------------------------
|
|
; INT 28H IDLE HANDLER
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE segment
|
|
assume cs:DXPMCODE
|
|
|
|
; -------------------------------------------------------
|
|
; PMIntr28 -- Protected mode handler for Idle Int 28h calls.
|
|
; The purpose of this routine is simply to cut down on the
|
|
; number of protected mode to real mode switches by ignoring
|
|
; many of the Int 28h idle calls made by the Windows PM
|
|
; kernel.
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public PMIntr28
|
|
|
|
PMIntr28 proc near
|
|
|
|
|
|
cld
|
|
push ds ;address our DGROUP
|
|
mov ds,selDgroupPM
|
|
assume ds:DGROUP
|
|
|
|
cmp Int28Filter,0 ;are we passing any through?
|
|
jz @f
|
|
|
|
inc Int28Count ;should this one be reflected?
|
|
jz i28_reflect
|
|
@@:
|
|
pop ds
|
|
iret ; no, just ignore it
|
|
|
|
i28_reflect: ; yes, reset count and
|
|
push ax ; reflecto to real mode
|
|
mov ax,Int28Filter
|
|
neg ax
|
|
mov Int28Count,ax
|
|
pop ax
|
|
pop ds
|
|
assume ds:NOTHING
|
|
|
|
jmp PMIntrEntryVector + 3*28h
|
|
|
|
PMIntr28 endp
|
|
|
|
; -------------------------------------------------------
|
|
subttl Real-Time Clock Int 70h Handler
|
|
page
|
|
; -------------------------------------------------------
|
|
; REAL-TIME CLOCK INT 70h HANDLER
|
|
; -------------------------------------------------------
|
|
|
|
; PMIntr70 -- Protected mode handler for Real-Time clock
|
|
; interrupts. This routine intercepts real-time clock
|
|
; interrupts, and may cause them to be ignored. On 286
|
|
; hardware, the mode switch time is a big problem in trying
|
|
; to service the 0.976 ms periodic interrupt. So, if this
|
|
; is a 286 machine, and periodic interrupts are enabaled,
|
|
; we EOI the slave & master PICs, and IRET. A Tandy 2500 XL
|
|
; machine was having a problem with the interrupt reflector
|
|
; stack overrunning because the PS/2 style mouse was causing
|
|
; mode switches while the RTC was programmed for periodic
|
|
; interrupts.
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public PMIntr70
|
|
|
|
PMIntr70 proc near
|
|
|
|
cld
|
|
push ds ;address our DGROUP
|
|
mov ds,selDgroupPM
|
|
assume ds:DGROUP
|
|
|
|
cmp idCpuType,3 ;assume we can mode switch fast enough
|
|
jae i70_reflect ; on 386 + processors
|
|
|
|
push ax ;on a 286, are periodic interrupts
|
|
mov al,0Bh ; enabled? Read clock register B
|
|
call ReadCMOS
|
|
|
|
and al,40h ;periodic interrupts enabled?
|
|
jz i70_286_reflect ; no, something else, so reflect it
|
|
|
|
mov al,0Ch ;read register C to clear int bits
|
|
call ReadCMOS
|
|
|
|
mov al,20h ;EOI the slave PIC
|
|
out INTB00,al
|
|
IO_Delay
|
|
out INTA00,al ;EOI the master PIC
|
|
|
|
pop ax ;back to the shadows again...
|
|
pop ds
|
|
iret
|
|
|
|
i70_286_reflect:
|
|
pop ax
|
|
|
|
i70_reflect: ;reflect interrupt to real mode
|
|
pop ds
|
|
assume ds:NOTHING
|
|
|
|
jmp PMIntrEntryVector + 3*70h
|
|
|
|
PMIntr70 endp
|
|
|
|
; -------------------------------------------------------
|
|
; ReadCMOS -- Read selected location from CMOS ram/Real-Time clock.
|
|
;
|
|
; in: al - CMOS location to read
|
|
; out: al - CMOS valus
|
|
; uses: All registers perserved
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public ReadCMOS
|
|
|
|
ReadCMOS proc near
|
|
|
|
out CMOSLoc,al
|
|
IO_Delay
|
|
in al,CMOSValue
|
|
ret
|
|
|
|
ReadCMOS endp
|
|
|
|
; -------------------------------------------------------
|
|
subttl Ignore Interrupt Handlers
|
|
page
|
|
; -------------------------------------------------------
|
|
; IGNORE INTERRUPT HANDLER
|
|
; -------------------------------------------------------
|
|
|
|
; PMIntrIgnore -- Service routine for protected mode interrupts
|
|
; that should be ignored, and not reflected to real mode.
|
|
; Currently used for:
|
|
;
|
|
; Int 30h - used to be Win/386 Virtualize I/O, now
|
|
; unused but no int handler in real mode
|
|
; Int 41h - Wdeb386 interface, no int handler in
|
|
; real mode
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public PMIntrIgnore
|
|
|
|
PMIntrIgnore proc near
|
|
|
|
iret
|
|
|
|
PMIntrIgnore endp
|
|
|
|
; -------------------------------------------------------
|
|
|
|
public PMIntr19
|
|
PMIntr19 proc near
|
|
|
|
push offset DXPMCODE:Reboot
|
|
call RZCall
|
|
|
|
bpRebootIDT df 0
|
|
|
|
Reboot:
|
|
mov ax,40h
|
|
mov es,ax
|
|
mov word ptr es:[0072h],1234h
|
|
lidt bpRebootIDT
|
|
int 3
|
|
|
|
PMIntr19 endp
|
|
|
|
DXPMCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
subttl XMS Driver Interface
|
|
page
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE segment
|
|
assume cs:DXPMCODE
|
|
|
|
; -------------------------------------------------------
|
|
; XMScontrol - This function implements a protected mode
|
|
; interface to a real mode XMS driver. Unlike other
|
|
; routines in this module, this routine is called by
|
|
; the user, not invoked via an INT instruction.
|
|
;
|
|
; Input: User's regs for XMS driver
|
|
; Output: regs from XMS driver
|
|
; Uses: none
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public XMScontrol
|
|
|
|
XMScontrol proc far
|
|
|
|
jmp short XMSentry ;'standard' XMS control function
|
|
nop ; just to be consistant
|
|
nop
|
|
nop
|
|
|
|
XMSentry:
|
|
|
|
; Modify the stack so it looks like we got here via an INT (except that
|
|
; we may still have interrupts enabled)
|
|
|
|
pushf
|
|
cld
|
|
|
|
push bp
|
|
mov bp,sp ;bp -> [BP] [FL] [IP] [CS]
|
|
push ax
|
|
push bx
|
|
|
|
mov ax,[bp+4]
|
|
mov bx,[bp+6]
|
|
xchg ax,[bp+2]
|
|
mov [bp+4],bx
|
|
mov [bp+6],ax ;bp -> [BP] [IP] [CS] [FL]
|
|
pop bx
|
|
pop ax
|
|
pop bp
|
|
|
|
; We don't support XMS function 0Bh (Move Extended Memory Block) because
|
|
; it requires mapping of data between hi/low memory. Maybe someday...
|
|
|
|
cmp ah,0Bh
|
|
jnz xms_2
|
|
xms_deny:
|
|
xor ax,ax ;if function 0Bh, return failure
|
|
mov bl,80h ; (ax = 0, bl = 80h-not implemented)
|
|
jmp short XMSret
|
|
xms_2:
|
|
|
|
; We are not really an Int handler, but close enough...
|
|
|
|
call EnterIntHandler ;build an interrupt stack frame
|
|
assume ds:DGROUP,es:DGROUP ; also sets up addressability
|
|
|
|
if 0
|
|
if VCPI
|
|
;
|
|
; If we're using VCPI, then fail the call. This is because XMS memory
|
|
; would not be useful in protected mode unless we paged it into our
|
|
; page tables.
|
|
;
|
|
cmp fVCPI,0
|
|
jz xms_3
|
|
call LeaveIntHandler
|
|
mov ax,0
|
|
mov dx,0
|
|
mov bl,80h ; BX = 80h-not implemented.
|
|
jmp XMSret
|
|
xms_3:
|
|
endif
|
|
endif
|
|
|
|
SwitchToRealMode
|
|
|
|
pop es ;load regs for driver
|
|
pop ds
|
|
assume ds:NOTHING,es:NOTHING,ss:DGROUP
|
|
popa
|
|
npopf
|
|
|
|
call lpfnXMSFunc ;call real mode driver
|
|
|
|
pushf ;rebuild stack frame
|
|
FCLI
|
|
cld
|
|
pusha
|
|
push ds
|
|
push es
|
|
|
|
mov bp,sp ;restore stack frame pointer
|
|
|
|
SwitchToProtectedMode
|
|
assume ds:DGROUP,es:DGROUP
|
|
|
|
call LeaveIntHandler
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
|
|
XMSret:
|
|
riret
|
|
|
|
XMScontrol endp
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
subttl Special Interrupt Handler Routines
|
|
page
|
|
; -------------------------------------------------------
|
|
;
|
|
; The following sets of routines handle interrupts that
|
|
; are function call interfaces and require special servicing
|
|
; by the Dos Extender. These interrupts are such things as
|
|
; the mouse driver function call interrupt, various PC BIOS
|
|
; function call interrupts, etc. Note that INT 21h (the Dos
|
|
; function call interrupt) is not handled here. These
|
|
; interrupts typically require that register values be modified
|
|
; and parameter data be copied between real mode memory and
|
|
; extended memory. The following conventions are used for these
|
|
; interrupt function handler routines.
|
|
;
|
|
; A stack is allocated from the interrupt reflector stack for these
|
|
; routines to use. This allows nested servicing of interrupts.
|
|
; A stack frame is built in the allocated stack which contains the
|
|
; following information:
|
|
; original caller's stack address
|
|
; caller's original flags and general registers (in pusha form)
|
|
; caller's original segment registers (DS & ES)
|
|
; flags and general registers to be passed to interrupt routine
|
|
; (initially the same as caller's original values)
|
|
; segment registers (DS & ES) to be passed to interrupt routine
|
|
; (initially set to the Dos Extender data segment address)
|
|
; This stack frame is built by the routine EnterIntHandler, and its
|
|
; format is defined by the structure INTRSTACK. The stack frame is
|
|
; destroyed and the processor registers set up for return to the user
|
|
; by the function LeaveIntHandler.
|
|
;
|
|
; For each interrupt, there is an entry function and an exit function.
|
|
; The entry function performs any modifications to parameter values and
|
|
; data buffering necessary before the interrupt service routine is called.
|
|
; The exit function performs any data buffering and register value
|
|
; modifications after return from the interrupt service routine.
|
|
;
|
|
; There are two sets of general registers and two sets of segment
|
|
; registers (DS & ES) on the stack frame. One set of register values
|
|
; has member names of the form intUserXX. The values in these stack
|
|
; frame members will be passed to the interrupt service routine when
|
|
; it is called, and will be loaded with the register values returned
|
|
; by the interrupt service routine. The other set of registers values
|
|
; has member names of the form pmUserXX. These stack frame members
|
|
; contain the original values in the registers on entry from the
|
|
; user program that called the interrupt.
|
|
;
|
|
; When we return to the original caller, we want to pass back the
|
|
; general registers as returned by the interrupt routine (and possibly
|
|
; modified by the exit handler), and the same segment registers as
|
|
; on entry, unless the interrupt routine returns a value in a segment
|
|
; register. (in this case, there must be some code in the exit routine
|
|
; to handle this). This means that when we return to the caller, we
|
|
; return the general register values from the intUserXX set of stack
|
|
; frame members, but we return the segment registers from the pmUserXX
|
|
; set of frame members. By doing it this way, we don't have to do
|
|
; any work for the case where the interrupt subfuntion doesn't require
|
|
; any parameter manipulation. NOTE however, this means that when
|
|
; manipulating register values to be returned to the user, the segment
|
|
; registers are treated opposite to the way the general registers are
|
|
; treated. For general registers, to return a value to the user,
|
|
; store it in a intUserXX stack frame member. To return a segment
|
|
; value to the user, store it in a pmUserXX stack frame member.
|
|
;
|
|
; -------------------------------------------------------
|
|
subttl BIOS Video Interrupt (Int 10h) Service Routine
|
|
page
|
|
; -------------------------------------------------------
|
|
; BIOS VIDEO INTERRUPT (INT 10h) SERVICE ROUTINE
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE segment
|
|
assume cs:DXPMCODE
|
|
|
|
; -------------------------------------------------------
|
|
; PMIntrVideo - Entry point into interrupt reflector code
|
|
; for IBM PC Bios video (int 10h) calls.
|
|
;
|
|
; Input: normal registers for Bios calls
|
|
; Output: normal register returns for Bios calls
|
|
; Errors: normal Bios errors
|
|
; Uses: as per Bios calls
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public PMIntrVideo
|
|
|
|
PMIntrVideo:
|
|
|
|
call EnterIntHandler ;build a stack frame and fix up the
|
|
cld ; return address so that the interrupt
|
|
;service routine will return to us.
|
|
;
|
|
; Perform fixups on the entry register values
|
|
call IntEntryVideo
|
|
;
|
|
; Execute the interrupt service routine
|
|
SwitchToRealMode
|
|
assume ss:DGROUP
|
|
pop es
|
|
pop ds
|
|
assume ds:NOTHING,es:NOTHING
|
|
popa
|
|
sub sp,8 ; make room for stack frame
|
|
push bp
|
|
mov bp,sp
|
|
push es
|
|
push ax
|
|
|
|
xor ax,ax
|
|
mov es,ax
|
|
mov [bp + 8],cs
|
|
mov [bp + 6],offset piv_10
|
|
mov ax,es:[10h*4]
|
|
mov [bp + 2],ax
|
|
mov ax,es:[10h*4 + 2]
|
|
mov [bp + 4],ax
|
|
pop ax
|
|
pop es
|
|
pop bp
|
|
retf
|
|
|
|
piv_10: pushf
|
|
FCLI
|
|
cld
|
|
pusha
|
|
push ds
|
|
push es
|
|
mov bp,sp ;restore stack frame pointer
|
|
SwitchToProtectedMode
|
|
assume ds:DGROUP,es:DGROUP
|
|
;
|
|
; Perform fixups on the return register values.
|
|
mov ax,[bp].pmUserAX ;get original function code
|
|
call IntExitVideo
|
|
;
|
|
; And return to the original caller.
|
|
call LeaveIntHandler
|
|
|
|
riret
|
|
|
|
; -------------------------------------------------------
|
|
; IntEntryVideo -- This routine performs any register
|
|
; fixups and data copying needed on entry to the
|
|
; PC BIOS video interrupt (Int 10h)
|
|
;
|
|
; Input: register values on stack frame
|
|
; Output: register values on stack frame
|
|
; Errors: none
|
|
; Uses: any registers modified,
|
|
; possibly modifies buffers rgbXfrBuf0 or rgbXfrBuf1
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public IntEntryVideo
|
|
|
|
IntEntryVideo:
|
|
|
|
cmp ah,10h
|
|
jnz ienv20
|
|
;
|
|
; Video palette control function. Check for subfunctions that require
|
|
; special actions.
|
|
ienv10: cmp al,2 ;update all palette registers?
|
|
jnz @F
|
|
mov cx,17 ;palette data is 17 bytes long
|
|
jmp short ienv70 ;go copy the data
|
|
;
|
|
@@: cmp al,9 ;read all palette registers
|
|
jz ienv72
|
|
;
|
|
cmp al,12h ;update video DAC color registers
|
|
jnz @F
|
|
mov cx,[bp].pmUserCX ;count of table entries is in caller CX
|
|
add cx,cx ;each entry is 3 bytes long
|
|
add cx,[bp].pmUserCX
|
|
jmp short ienv70 ;go copy the data down
|
|
|
|
@@: cmp al,17h ;read a block of video DAC registers
|
|
jz ienv72
|
|
;
|
|
jmp short ienv90
|
|
;
|
|
;
|
|
ienv20: cmp ah,11h
|
|
jnz ienv30
|
|
;
|
|
; Character generator interface function.
|
|
; NOTE: a number of subfunctions of function 11h need to have munging
|
|
; and data buffering performed. However, function 30h is the only
|
|
; one used by Codeview, so this is the only one currently implemented.
|
|
; For this one, nothing needs to be done on entry, only on exit.
|
|
jmp short ienv90
|
|
;
|
|
;
|
|
ienv30: cmp ah,1Bh
|
|
jnz ienv40
|
|
;
|
|
; Video BIOS functionality/state information.
|
|
; On entry, we need to fix up ES:DI to point to our buffer.
|
|
mov [bp].intUserDI,offset DGROUP:rgbXfrBuf0
|
|
jmp short ienv90
|
|
;
|
|
;
|
|
ienv40:
|
|
jmp short ienv90
|
|
;
|
|
; Copy the buffer from the user ES:DX to our transfer buffer and set
|
|
; the value to DX passed to the interrupt routine to point to our buffer.
|
|
ienv70: cld
|
|
jcxz ienv90
|
|
push ds
|
|
mov si,[bp].pmUserDX
|
|
mov ds,[bp].pmUserES
|
|
mov di,offset DGROUP:rgbXfrBuf1
|
|
cld
|
|
rep movsb
|
|
pop ds
|
|
;
|
|
ienv72: mov [bp].intUserDX,offset DGROUP:rgbXfrBuf1
|
|
jmp short ienv90
|
|
|
|
;
|
|
; All done
|
|
ienv90:
|
|
ret
|
|
|
|
; -------------------------------------------------------
|
|
; IntExitVideo: This routine performs any register
|
|
; fixups and data copying needed on exit from the
|
|
; PC BIOS video interrupt (Int 10h).
|
|
;
|
|
; Input: register values on stack frame
|
|
; Output: register values on stack frame
|
|
; Errors: none
|
|
; Uses: any registers modified
|
|
; possibly modifies buffers rgbXfrBuf0 or rgbXfrBuf1
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public IntExitVideo
|
|
|
|
IntExitVideo:
|
|
|
|
cmp ah,10h
|
|
jnz iexv20
|
|
;
|
|
; Palette control function.
|
|
cmp al,9 ;read palette data function
|
|
jnz @F
|
|
mov cx,17
|
|
jmp short iexv70
|
|
;
|
|
@@: cmp al,17h ;read video DAC registers
|
|
jnz @F
|
|
mov cx,[bp].pmUserCX ;each entry in table is 3 bytes long
|
|
add cx,cx
|
|
add cx,[bp].pmUserCX
|
|
jmp short iexv70
|
|
;
|
|
@@: jmp short iexv72
|
|
;
|
|
;
|
|
iexv20: cmp ah,11h
|
|
jnz iexv30
|
|
;
|
|
; Character generator interface function.
|
|
; NOTE: a number of subfunctions of function 11h need to have munging
|
|
; and data buffering performed. However, function 30h is the only
|
|
; one used by Codeview, so this is the only one currently implemented
|
|
cmp al,30h
|
|
jnz @F
|
|
mov ax,[bp].intUserES ;get the paragraph address returned by BIOS
|
|
mov bx,STD_DATA
|
|
call ParaToLDTSelector ;get a selector for that address
|
|
mov [bp].pmUserES,ax ;store the selector so that it will be
|
|
; returned to the caller
|
|
@@: jmp short iexv90
|
|
;
|
|
;
|
|
iexv30: cmp ah,1Bh
|
|
jnz iexv40
|
|
;
|
|
; Video BIOS functionality/state information.
|
|
; On exit, we need to fix up the pointer at the beginning of the
|
|
; data put in our buffer by the BIOS, and then transfer the buffer up
|
|
; to the user.
|
|
mov ax,word ptr rgbXfrBuf0[2] ;get segment of pointer to
|
|
; 'static functionallity table'
|
|
mov bx,STD_DATA
|
|
call ParaToLDTSelector ;convert paragraph to selector
|
|
mov word ptr rgbXfrBuf0[2],ax ;store back into table
|
|
push es
|
|
mov si,offset rgbXfrBuf0 ;pointer to our copy of the table
|
|
mov di,[bp].pmUserDI ;where the user wants it
|
|
mov [bp].intUserDi,di ;restore the DI returned to the user
|
|
mov es,[bp].pmUserES
|
|
mov cx,64 ;the table is 64 bytes long
|
|
cld
|
|
rep movsb ;copy the table to the user's buffer
|
|
pop es
|
|
|
|
jmp short iexv90
|
|
;
|
|
;
|
|
iexv40:
|
|
jmp short iexv90
|
|
|
|
;
|
|
; Copy data from our buffer to the caller's buffer pointed to by ES:DX
|
|
iexv70: cld
|
|
push es
|
|
mov di,[bp].pmUserDX
|
|
mov es,[bp].pmUserES
|
|
mov si,offset DGROUP:rgbXfrBuf1
|
|
rep movsb
|
|
pop es
|
|
;
|
|
; Restore the caller's DX
|
|
iexv72: mov ax,[bp].pmUserDX
|
|
mov [bp].intUserDX,ax
|
|
;
|
|
; All done
|
|
iexv90:
|
|
ret
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
subttl BIOS Misc. Interrupt (Int 15h) Service Routine
|
|
page
|
|
; -------------------------------------------------------
|
|
; BIOS MISC. INTERRUPT (INT 15h) SERVICE ROUTINE
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE segment
|
|
assume cs:DXPMCODE
|
|
|
|
; -------------------------------------------------------
|
|
; PMIntrMisc -- Entry point into the interrupt processing code
|
|
; for the BIOS misc functions interrupt (INT 15h).
|
|
;
|
|
; Input: normal registers for Bios calls
|
|
; Output: normal register returns for Bios calls
|
|
; Errors: normal Bios errors
|
|
; Uses: as per Bios calls
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public PMIntrMisc
|
|
|
|
PMIntrMisc:
|
|
;
|
|
call EnterIntHandler ;build a stack frame and fix up the
|
|
cld ; return address so that the interrupt
|
|
;service routine will return to us.
|
|
;
|
|
; Perform fixups on the entry register values
|
|
call IntEntryMisc
|
|
;
|
|
; Execute the interrupt service routine
|
|
SwitchToRealMode
|
|
assume ss:DGROUP
|
|
pop es
|
|
pop ds
|
|
assume ds:NOTHING,es:NOTHING
|
|
popa
|
|
sub sp,8 ; make room for stack frame
|
|
push bp
|
|
mov bp,sp
|
|
push es
|
|
push ax
|
|
|
|
xor ax,ax
|
|
mov es,ax
|
|
mov [bp + 8],cs
|
|
mov [bp + 6],offset pim_10
|
|
mov ax,es:[15h*4]
|
|
mov [bp + 2],ax
|
|
mov ax,es:[15h*4 + 2]
|
|
mov [bp + 4],ax
|
|
pop ax
|
|
pop es
|
|
pop bp
|
|
retf
|
|
|
|
pim_10: pushf
|
|
FCLI
|
|
cld
|
|
pusha
|
|
push ds
|
|
push es
|
|
mov bp,sp ;restore stack frame pointer
|
|
SwitchToProtectedMode
|
|
assume ds:DGROUP,es:DGROUP
|
|
;
|
|
; Perform fixups on the return register values.
|
|
mov ax,[bp].pmUserAX ;get original function code
|
|
call IntExitMisc
|
|
;
|
|
; And return to the original caller.
|
|
call LeaveIntHandler
|
|
riret
|
|
|
|
; -------------------------------------------------------
|
|
; MISC INTERRUPT SUPPORT ROUTINES
|
|
; -------------------------------------------------------
|
|
;
|
|
; IntEntryMisc -- This function performs data transfer
|
|
; and register translation on entry to the BIOS Misc.
|
|
; functions interrupt. (INT 15h).
|
|
;
|
|
; Input: AX - BIOS function being performed
|
|
; Output:
|
|
; Errors:
|
|
; Uses: All registers preserved
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public IntEntryMisc
|
|
|
|
IntEntryMisc:
|
|
|
|
; Map requests to set the PS/2 Pointing Device Handler Address
|
|
|
|
cmp ax,0C207h ;PS/2 Set Pointing Device Handler adr?
|
|
jnz iem90
|
|
|
|
mov ax,[bp].pmUserBX ;User's ES:BX -> handler
|
|
mov word ptr lpfnUserPointingHandler,ax
|
|
mov ax,[bp].pmUserES
|
|
mov word ptr [lpfnUserPointingHandler+2],ax
|
|
|
|
mov ax,segDXCodePM ;pass BIOS address of our handler
|
|
mov [bp].intUserES,ax
|
|
mov ax,offset PointDeviceHandler
|
|
mov [bp].intUserBX,ax
|
|
|
|
iem90:
|
|
ret
|
|
|
|
; -------------------------------------------------------
|
|
; IntExitMisc -- This function performs data transfer
|
|
; and register translation on exit from the BIOS Misc.
|
|
; Functions interrupt (INT 15h).
|
|
;
|
|
; Input: AX - BIOS function being performed
|
|
; Output:
|
|
; Errors:
|
|
; Uses: All registers preserved
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public IntExitMisc
|
|
|
|
IntExitMisc:
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push dx
|
|
;
|
|
; Check for function 0C0h - Return System Configuration Parameters
|
|
cmp ah,0C0h
|
|
jnz ixmi30
|
|
test [bp].intUserFL,1 ;check if the bios call returned an error
|
|
jnz ixmi90 ;(carry flag set in returned flags)
|
|
;
|
|
; The BIOS call succeeded. This means that ES:BX points to a configuration
|
|
; vector. We need to fix up the segment to be a selector.
|
|
mov dx,[bp].intUserES
|
|
cmp dx,0F000h ;does it point to normal BIOS segment
|
|
jnz ixmi22
|
|
mov ax,SEL_BIOSCODE or STD_RING
|
|
jmp short ixmi24
|
|
|
|
ixmi22: call ParaToLinear
|
|
mov cx,0FFFFh
|
|
mov ax,SEL_USERSCR or STD_TBL_RING
|
|
cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_DATA>
|
|
ixmi24: mov [bp].pmUserES,ax
|
|
jmp short ixmi90
|
|
|
|
; Chack for function 0C207h - PS/2 Set Pointing Device Handler Address
|
|
|
|
ixmi30:
|
|
cmp ax,0C207h
|
|
jne ixmi90
|
|
|
|
mov ax,[bp].pmUserBX ;restore user's BX
|
|
mov [bp].intUserBX,ax
|
|
|
|
; All done
|
|
ixmi90:
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
subttl Mouse Function Interrupt (Int 33h) Service Routine
|
|
page
|
|
; -------------------------------------------------------
|
|
; MOUSE FUNCTION INTERRUPT (INT 33h) SERVICE ROUTINE
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE segment
|
|
assume cs:DXPMCODE
|
|
|
|
; -------------------------------------------------------
|
|
; PMIntrMouse - Entry point into interrupt reflector code
|
|
; for mouse driver (int 33h) calls.
|
|
;
|
|
; Input: normal registers for mouse calls
|
|
; Output: normal register returns for mouse calls
|
|
; Errors: normal mouse errors
|
|
; Uses: as per mouse calls
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public PMIntrMouse
|
|
|
|
PMIntrMouse:
|
|
;
|
|
call EnterIntHandler ;build a stack frame and fix up the
|
|
cld ; return address so that the interrupt
|
|
;service routine will return to us.
|
|
;
|
|
; Perform fixups on the entry register values
|
|
call IntEntryMouse
|
|
;
|
|
; Execute the interrupt service routine
|
|
SwitchToRealMode
|
|
assume ss:DGROUP
|
|
pop es
|
|
pop ds
|
|
assume ds:NOTHING,es:NOTHING
|
|
popa
|
|
sub sp,8 ; make room for stack frame
|
|
push bp
|
|
mov bp,sp
|
|
push es
|
|
push ax
|
|
|
|
xor ax,ax
|
|
mov es,ax
|
|
mov [bp + 8],cs
|
|
mov [bp + 6],offset pimo_10
|
|
mov ax,es:[33h*4]
|
|
mov [bp + 2],ax
|
|
mov ax,es:[33h*4 + 2]
|
|
mov [bp + 4],ax
|
|
pop ax
|
|
pop es
|
|
pop bp
|
|
retf
|
|
|
|
pimo_10: pushf
|
|
FCLI
|
|
cld
|
|
pusha
|
|
push ds
|
|
push es
|
|
mov bp,sp ;restore stack frame pointer
|
|
SwitchToProtectedMode
|
|
assume ds:DGROUP,es:DGROUP
|
|
;
|
|
; Perform fixups on the return register values.
|
|
mov ax,[bp].pmUserAX ;get original function code
|
|
call IntExitMouse
|
|
;
|
|
; And return to the original caller.
|
|
call LeaveIntHandler
|
|
riret
|
|
|
|
; -------------------------------------------------------
|
|
; MOUSE SUPPORT ROUTINES
|
|
; -------------------------------------------------------
|
|
|
|
; IntEntryMouse -- This function performs data transfer and
|
|
; register translation on entry to mouse driver functions.
|
|
; (INT 33h)
|
|
;
|
|
; Input: AX - mouse function being performed
|
|
; Output:
|
|
; Errors:
|
|
; Uses: NOTHING
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public IntEntryMouse
|
|
|
|
IntEntryMouse:
|
|
cld
|
|
push ax
|
|
push cx
|
|
push si
|
|
push di
|
|
;
|
|
cmp al,9 ;Set graphics cursor block?
|
|
jnz ment10
|
|
;
|
|
; The user is setting a graphics cursor. We need to copy the masks
|
|
; down to low memory so that the mouse driver can get at them and then
|
|
; fix up the pointer in DX.
|
|
mov cx,32
|
|
jmp short ment92
|
|
;
|
|
; Mouse interrupt handler establishment
|
|
ment10: cmp al,12 ;Set user defined interrupt subroutine ?
|
|
jnz ment20
|
|
;
|
|
; This command has the effect of causing a call to the address es:ds
|
|
; Whenever an event of one of the types specified by the mask in cx.
|
|
; The address es:dx must be saved in lpfnUserMouseHandler and the
|
|
; real mode address of MouseInterruptHandler substituted.
|
|
mov ax,[bp].pmUserDX ; Load users handler offset
|
|
mov word ptr lpfnUserMouseHandler,ax ; Store for future use
|
|
mov ax,[bp].pmUserES ; Load users handler segment value
|
|
mov word ptr lpfnUserMouseHandler + 2,ax ; Store for future use
|
|
mov ax,segDXCodePM ; Load real mode code segment value
|
|
mov [bp].intUserES,ax ; Store in real mode es register image
|
|
mov ax,offset MouseInterruptHandler ; Load handler offset
|
|
mov [bp].intUserDX,ax ; Store in real mode dx register image
|
|
jmp short ment99 ;Return
|
|
;
|
|
ment20: cmp al,20
|
|
jc ment99
|
|
jnz ment30
|
|
;
|
|
; This is the swap interrupt subroutine function. Not currently implemented
|
|
jmp short ment99
|
|
;
|
|
ment30: cmp al,22 ;Save mouse driver state?
|
|
jnz ment40
|
|
;
|
|
; This is the save mouse driver state function. We need to pass a pointer
|
|
; to the transer buffer down to the mouse driver.
|
|
mov ax,npXfrBuf1
|
|
mov [bp].intUserDX,ax
|
|
jmp short ment99
|
|
|
|
ment40: cmp al,23 ;Restore mouse driver state?
|
|
jnz ment99
|
|
;
|
|
; This is the restore mouse driver state function. We need to copy the
|
|
; mouse state buffer from the pm user location to the transfer buffer,
|
|
; and then pass the pointer to the transfer buffer on to the mouse driver.
|
|
mov cx,cbMouseState
|
|
jcxz ment99
|
|
;
|
|
; Transfer the data pointed to by the user ES:DX to the scratch buffer, and
|
|
; fix up the pointer that is passed on to the mouse driver.
|
|
ment92: mov si,[bp].pmUserDX
|
|
mov di,npXfrBuf1
|
|
mov [bp].intUserDX,di
|
|
push ds
|
|
mov ds,[bp].pmUserES
|
|
cld
|
|
rep movs word ptr [di],word ptr [si]
|
|
pop ds
|
|
;
|
|
ment99: pop di
|
|
pop si
|
|
pop cx
|
|
pop ax
|
|
ret
|
|
|
|
; -------------------------------------------------------
|
|
; IntExitMouse -- This function performs data transfer and
|
|
; register translation on exit from mouse driver functions.
|
|
; (INT 33h)
|
|
;
|
|
; Input: AX - mouse function being performed
|
|
; Output:
|
|
; Errors:
|
|
; Uses:
|
|
|
|
assume ds:DGROUP,es:DGROUP,ss:NOTHING
|
|
public IntExitMouse
|
|
|
|
IntExitMouse:
|
|
cld
|
|
cmp al,21 ;get state buffer size?
|
|
jnz mxit20
|
|
;
|
|
; We need to remember the state buffer size, so that later we will know
|
|
; how many bytes to transfer when we do the save/restore state fucntions.
|
|
mov ax,[bp].intUserBX
|
|
mov cbMouseState,ax
|
|
return
|
|
;
|
|
mxit20: cmp al,22 ;Save mouse driver state?
|
|
jnz mxit30
|
|
;
|
|
; We need to restore the original values of ES:DX and transfer the mouse
|
|
; state data from the real mode buffer to the user's protected mode buffer.
|
|
mov cx,cbMouseState
|
|
jcxz mxit28
|
|
push es
|
|
mov si,npXfrBuf1
|
|
mov di,[bp].pmUserDX
|
|
mov [bp].intUserDX,di
|
|
mov es,[bp].pmUserES
|
|
rep movs byte ptr [di],byte ptr [si]
|
|
pop es
|
|
mxit28: return
|
|
;
|
|
mxit30: cmp al,23 ;Restore mouse driver state?
|
|
jnz mxit99
|
|
mov ax,[bp].pmUserDX
|
|
mov [bp].intUserDX,ax
|
|
;
|
|
mxit99: ret
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
subttl PM Interrupt Support Routines
|
|
page
|
|
; -------------------------------------------------------
|
|
; PM INTERRUPT SUPPORT ROUTINES
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE segment
|
|
assume cs:DXPMCODE
|
|
|
|
; -------------------------------------------------------
|
|
; EnterIntHandler -- This routine will allocate a stack
|
|
; frame on the interrupt reflector stack and make
|
|
; a copy of the registers on the allocated stack.
|
|
;
|
|
; Note: This routine expects the current stack to contain a near
|
|
; return address and a normal [IP] [CS] [FL] interrupt stack
|
|
; frame. Don't have anything else on the stack before calling
|
|
; this routine!
|
|
;
|
|
; Note: This routine disables interrupts, and leaves them disabled.
|
|
; Most callers already have them disabled, so it doesn't
|
|
; really make a difference, except that this routine
|
|
; requires that they be disabled.
|
|
;
|
|
; Input: none
|
|
; Output: stack frame set up
|
|
; Errors: none
|
|
; Uses: all registers preserved
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public EnterIntHandler
|
|
|
|
EnterIntHandler proc near
|
|
|
|
FCLI ;we really want int's disabled (and
|
|
; XMScontrol doesn't do that)
|
|
push ds
|
|
mov ds,selDgroupPM ;save user's DS and address our DGROUP
|
|
assume ds:DGROUP
|
|
pop regUserDS
|
|
|
|
push bp
|
|
mov bp,sp ;bp -> [BP] [IP] [IP] [CS] [FL]
|
|
push word ptr [bp+8]
|
|
pop regUserFL ;user's flags before doing INT
|
|
pop bp
|
|
|
|
pop pfnReturnAddr ;near return to our immediate caller
|
|
|
|
mov regUserSS,ss ;save caller's stack address
|
|
mov regUserSP,sp
|
|
ASSERT_REFLSTK_OK
|
|
mov ss,selDgroupPM ;switch to interrupt reflector stack
|
|
mov sp,pbReflStack
|
|
sub pbReflStack,CB_STKFRAME ;adjust pointer to next stack frame
|
|
FIX_STACK
|
|
|
|
; Build the stack frame. The stack frame contains the following:
|
|
; dword & word parameter locations
|
|
; original caller's stack address
|
|
; caller's original flags and general registers (in pusha form)
|
|
; caller's original segment registers (DS & ES)
|
|
; flags and general registers to be passed to interrupt routine
|
|
; (initially the same as caller's original values)
|
|
; segment registers (DS & ES) to be passed to interrupt routine
|
|
; (initially set to the Dos Extender data segment address)
|
|
;
|
|
; The parameter words and then the caller's original register values go on top.
|
|
|
|
sub sp,8 ;space for a dd & 2 dw's
|
|
|
|
push regUserSP
|
|
push regUserSS
|
|
push regUserFL
|
|
pusha
|
|
push regUserDS
|
|
push es
|
|
|
|
; Now, put all of the general registers, and values for the segment
|
|
; registers to be passed to the interrupt service routine. We pass
|
|
; the Dos Extender data segment address to the interrupt routine.
|
|
|
|
push regUserFL
|
|
pusha
|
|
IFDEF ROM
|
|
push segDXData
|
|
push segDXData
|
|
ELSE
|
|
push segDXDataPM
|
|
push segDXDataPM
|
|
ENDIF
|
|
|
|
; And we are done.
|
|
|
|
mov bp,sp ;set up frame pointer
|
|
mov es,selDgroupPM
|
|
jmp pfnReturnAddr ;return to the caller.
|
|
|
|
EnterIntHandler endp
|
|
|
|
|
|
; -------------------------------------------------------
|
|
; LeaveIntHandler -- This routine will restore the user registers,
|
|
; release the stack frame, and restore the original user's stack
|
|
; for exit from an interrupt reflector routine.
|
|
;
|
|
; Note: Interrupts must be off when this routine is called.
|
|
;
|
|
; Input: none
|
|
; Output: none
|
|
; Errors: none
|
|
; Uses: All registers modified
|
|
|
|
assume ds:DGROUP,es:NOTHING,ss:NOTHING
|
|
public LeaveIntHandler
|
|
|
|
LeaveIntHandler proc near
|
|
|
|
FCLI
|
|
pop pfnReturnAddr
|
|
|
|
; The copy of the register values returned from the interrupt routine
|
|
; (and then possibly modified by the exit handler for the particular
|
|
; interrupt) are what gets returned to the caller. We discard the original
|
|
; register values saved on entry. (They were there so that the exit
|
|
; routine could refer to them if necessary)
|
|
|
|
add sp,4 ;skip over interrupt service routine's
|
|
; segment register values
|
|
popa ;restore general register values
|
|
pop regUserFL ;flags returned by interrupt routine
|
|
pop es ;get segment registers from pmUserES
|
|
pop regUserDS ; and pmUserDS
|
|
add sp,18 ;skip over the original user registers
|
|
; and flags
|
|
pop regUserSS ;original interrupted routine's stack
|
|
pop regUserSP
|
|
mov regUserAX,ax
|
|
|
|
; Switch back to the original user's stack.
|
|
|
|
ASSERT_REFLSTK_OK
|
|
ASSERT_CLI
|
|
CHECK_STACK
|
|
mov ss,regUserSS
|
|
mov sp,regUserSP
|
|
add pbReflStack,CB_STKFRAME
|
|
ASSERT_REFLSTK_OK
|
|
|
|
; We need to replace the image of the flags in the original int return
|
|
; address on the user's stack with the new flags returned from the interrupt
|
|
; service routine.
|
|
|
|
push bp
|
|
mov bp,sp ;stack -> BP IP CS FL
|
|
mov ax,regUserFL ;flags returned by interrupt service routine
|
|
and ax,0BFFFh ;clear the nested task flag
|
|
and [bp+6],0300h ;clear all but the interrupt and trace flags
|
|
; in the caller's original flags
|
|
or [bp+6],ax ;combine in the flags returned by the
|
|
; interrupt service routine. This will cause
|
|
; us to return to the original routine with
|
|
; interrupts on if they were on when the
|
|
; interrupt occured, or if the ISR returned
|
|
; with them on.
|
|
pop bp
|
|
|
|
; And now, return to the caller.
|
|
|
|
push pfnReturnAddr
|
|
mov ax,regUserAX
|
|
mov ds,regUserDS
|
|
assume ds:NOTHING
|
|
ret
|
|
|
|
LeaveIntHandler endp
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
subttl Mouse Interrupt Callback Function Handler
|
|
page
|
|
; -------------------------------------------------------
|
|
; MOUSE INTERRUPT CALLBACK FUNCTION HANDLER
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE segment
|
|
assume cs:DXCODE
|
|
|
|
; -------------------------------------------------------
|
|
; MouseInterruptHandler -- This routine is the entry point for
|
|
; user requested mouse event interrupts. It switches the
|
|
; processor to protected mode and transfers control to the
|
|
; user protected mode mouse handling routine. When that
|
|
; completes, it switches back to real mode and returns control
|
|
; to the mouse driver.
|
|
; Entry to this routine will have been requested by an
|
|
; INT 33H code 12 with the real address of this routine
|
|
; substituted for the users entry point.
|
|
; The address of the user specified mouse handler as specified
|
|
; in the original INT 33H is stored in the variable
|
|
; lpfnUserMouseHandler.
|
|
;
|
|
; Input: none
|
|
; Output: none
|
|
; Errors: none
|
|
; Uses: The segment registers are explicitly preserved by
|
|
; this routine. Other registers are as preserved or
|
|
; modified by the users mouse handler.
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public MouseInterruptHandler
|
|
|
|
MouseInterruptHandler proc far
|
|
;
|
|
; On entry, the stack layout is:
|
|
; [2] CS - System mouse handler code segment
|
|
; [0] IP - System mouse handler return offset
|
|
;
|
|
|
|
push es
|
|
push ds
|
|
pushf
|
|
FCLI
|
|
cld
|
|
IFDEF ROM
|
|
SetRMDataSeg
|
|
ELSE
|
|
mov ds,selDgroup
|
|
ENDIF
|
|
assume ds:DGROUP
|
|
pop regUserFL
|
|
;
|
|
; Allocate a new stack frame, and then switch to the local stack
|
|
; frame.
|
|
mov regUserSP,sp ;save entry stack pointer so we can restore it
|
|
mov regUSerSS,ss ;save segment too
|
|
IFDEF ROM
|
|
push ds
|
|
pop ss
|
|
ELSE
|
|
mov ss,selDgroup ;switch to our own stack frame
|
|
ENDIF
|
|
ASSERT_REFLSTK_OK
|
|
mov sp,pbReflStack
|
|
sub pbReflStack,CB_STKFRAME ;adjust pointer to next stack frame
|
|
FIX_STACK
|
|
;
|
|
; We are now running on our own stack, so we can switch into protected mode.
|
|
push ax ;preserve caller's AX
|
|
SwitchToProtectedMode
|
|
pop ax
|
|
;
|
|
; Build a far return frame on the stack so that the user's
|
|
; routine will return to us when it is finished.
|
|
push regUserSS ; save system mouse handler stack address
|
|
push regUserSP ; so we can restore it later
|
|
push ds
|
|
push cs
|
|
push offset mih50
|
|
;
|
|
; Build an IRET frame on the stack to use to transfer control to the
|
|
; user's protected mode routine
|
|
push regUserFL
|
|
push word ptr lpfnUserMouseHandler+2 ;push segment of user routine
|
|
push word ptr lpfnUserMouseHandler ;push offset of user routine
|
|
;
|
|
; At this point the interrupt reflector stack looks like this:
|
|
;
|
|
; [14] stack segment of original stack
|
|
; [12] stack pointer of original stack
|
|
; [10] real mode dos extender data segment
|
|
; [8] segment of return address back to here
|
|
; [6] offset of return address back here
|
|
; [4] Users flags
|
|
; [2] segment of user routine
|
|
; [0] offset of user routine
|
|
;
|
|
; Execute the users mouse handler
|
|
iret
|
|
;
|
|
; The users handler will return here after it is finsished.
|
|
mih50: FCLI
|
|
cld
|
|
pop ds
|
|
pop regUserSP
|
|
pop regUserSS
|
|
;
|
|
; Switch back to real mode.
|
|
push ax ;preserve AX
|
|
SwitchToRealMode
|
|
pop ax
|
|
CHECK_STACK
|
|
;
|
|
; Switch back to the original stack.
|
|
mov ss,regUserSS
|
|
mov sp,regUserSP
|
|
ASSERT_REFLSTK_OK
|
|
;
|
|
; Deallocate the stack frame that we are using.
|
|
add pbReflStack,CB_STKFRAME
|
|
ASSERT_REFLSTK_OK
|
|
;
|
|
; And return to the original interrupted program.
|
|
pop ds
|
|
pop es
|
|
|
|
ret
|
|
|
|
MouseInterruptHandler endp
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
subttl PS/2 Pointing Device Handler
|
|
page
|
|
; -------------------------------------------------------
|
|
; PS/2 POINTING DEVICE HANDLER
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE segment
|
|
assume cs:DXCODE
|
|
|
|
; -------------------------------------------------------
|
|
; PointDeviceHandler -- This routine is the entry point for
|
|
; the PS/2 Pointing Device Handler. It switches the
|
|
; processor to protected mode and transfers control to the
|
|
; user pointing device handler. When that completes,
|
|
; it switches back to real mode and returns control to
|
|
; the PS/2 BIOS.
|
|
;
|
|
; Note: The BIOS calls us with interrutps enabled!
|
|
|
|
; Input: none
|
|
; Output: none
|
|
; Errors: none
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public PointDeviceHandler
|
|
|
|
PointDeviceHandler proc far
|
|
|
|
; On entry, the stack layout is:
|
|
;
|
|
; [10] status
|
|
; [8] X coordinate
|
|
; [6] Y coordinate
|
|
; [4] Z coordinate
|
|
; [2] CS - PS/2 BIOS code segment
|
|
; [0] IP - PS/2 BIOS return offset
|
|
|
|
cld
|
|
push es ;save PS/2 BIOS ds/es on it's stack
|
|
push ds
|
|
|
|
IFDEF ROM
|
|
push ax
|
|
GetRMDataSeg
|
|
mov ds,ax
|
|
mov es,ax
|
|
pop ax
|
|
ELSE
|
|
mov ds,selDgroup ;addressability to DOSX DGROUP
|
|
push ds
|
|
pop es
|
|
ENDIF
|
|
assume ds:DGROUP,es:DGROUP
|
|
|
|
FCLI ;protect global regUserXX vars
|
|
|
|
; Allocate a new stack frame, and then switch to the local stack
|
|
; frame.
|
|
|
|
mov regUserSP,sp ;save entry stack pointer so we can restore it
|
|
mov regUSerSS,ss ;save segment too
|
|
IFDEF ROM
|
|
push ds
|
|
pop ss
|
|
ELSE
|
|
ASSERT_REFLSTK_OK
|
|
mov ss,selDgroup ;switch to our own stack frame
|
|
ENDIF
|
|
mov sp,pbReflStack
|
|
sub pbReflStack,CB_STKFRAME ;adjust pointer to next stack frame
|
|
FIX_STACK
|
|
|
|
push regUserSS ;save PS/2 BIOS stack address
|
|
push regUserSP ; so we can restore it later
|
|
|
|
push SEL_DXDATA or STD_RING ;DOSX DS to be poped in PM
|
|
|
|
sub sp,4*2 ;temp save the general regs further down the
|
|
pusha ; stack, they'll get poped in a little while
|
|
|
|
; Copy PS/2 pointing device stack info to our (soon to be) protected mode stack
|
|
|
|
mov si,regUserSP ;PS/2 stack pointer
|
|
mov ds,regUserSS ;PS/2 stack segment
|
|
assume ds:NOTHING
|
|
|
|
FSTI ;no more references to global regUserXX vars
|
|
|
|
add si,4*2 ;skip over es,ds,cs,ip
|
|
mov di,sp ;loc for pointing device
|
|
add di,8*2 ; data on our stack
|
|
mov cx,4
|
|
cld
|
|
rep movsw
|
|
|
|
push es ;restore ds = DGROUP
|
|
pop ds
|
|
assume ds:DGROUP
|
|
|
|
; We are now running on our own stack, so we can switch into protected mode.
|
|
|
|
SwitchToProtectedMode ;disables interrupts again
|
|
FSTI ; but we don't want them disabled
|
|
|
|
popa ;restore general registers
|
|
|
|
; At this point the stack looks like this:
|
|
;
|
|
; [12] stack segment of original stack
|
|
; [10] stack pointer of original stack
|
|
; [8] protect mode dos extender data segment
|
|
; [6] status
|
|
; [4] X coordinate
|
|
; [2] Y coordinate
|
|
; [0] Z coordinate
|
|
|
|
; Execute the user's pointing device handler
|
|
|
|
call [lpfnUserPointingHandler]
|
|
|
|
; The users handler will return here after it is finsished.
|
|
|
|
pdh50:
|
|
cld
|
|
add sp,4*2 ;discard pointing device info
|
|
pop ds
|
|
|
|
FCLI ;protect global regUserXX vars
|
|
pop regUserSP
|
|
pop regUserSS
|
|
|
|
; Switch back to real mode.
|
|
|
|
push ax ;preserve AX
|
|
SwitchToRealMode
|
|
pop ax
|
|
|
|
; Switch back to the original stack.
|
|
|
|
CHECK_STACK
|
|
mov ss,regUserSS
|
|
mov sp,regUserSP
|
|
|
|
; Deallocate the stack frame that we are using.
|
|
|
|
ASSERT_REFLSTK_OK
|
|
add pbReflStack,CB_STKFRAME
|
|
ASSERT_REFLSTK_OK
|
|
|
|
; And return to the PS/2 BIOS
|
|
|
|
FSTI ;we came in with ints enabled
|
|
|
|
pop ds
|
|
pop es
|
|
|
|
ret
|
|
|
|
PointDeviceHandler endp
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
; PROTECTED MODE FAULT HANDLERS
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE segment
|
|
assume cs:DXPMCODE
|
|
|
|
;------------------------------------------------------------------
|
|
; TrapHandler -- Handle Protect Mode Processor Exceptions.
|
|
;
|
|
; Stack layout inside of this routine:
|
|
; [34] user SS \
|
|
; [32] user SP |
|
|
; [30] user flags |_ placed by PMFaultAnalyzer
|
|
; [28] user cs |
|
|
; [26] user ip |
|
|
; [24] error code /
|
|
; [22] PMFaultReflector return CS
|
|
; [20] PMFaultReflector return IP
|
|
; [18] AX \
|
|
; [16] CX |
|
|
; [14] DX |
|
|
; [12] BX |- placed by PUSHA instruction
|
|
; [10] SP |
|
|
; [8] BP |
|
|
; [6] SI |
|
|
; [4] DI /
|
|
; [2] DS
|
|
; [0] ES
|
|
|
|
regSS equ [bp+34]
|
|
regSP equ [bp+32]
|
|
regFL equ [bp+30]
|
|
regCS equ [bp+28]
|
|
regIP equ [bp+26]
|
|
idError equ [bp+24]
|
|
|
|
regRetCS equ [bp+22]
|
|
regRetIP equ [bp+20]
|
|
|
|
regAX equ [bp+18]
|
|
regCX equ [bp+16]
|
|
regDX equ [bp+14]
|
|
regBX equ [bp+12]
|
|
regBP equ [bp+8]
|
|
regSI equ [bp+6]
|
|
regDI equ [bp+4]
|
|
regDS equ [bp+2]
|
|
regES equ [bp+0]
|
|
|
|
|
|
public TrapHandler
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
TrapHandler proc far
|
|
|
|
pusha
|
|
push ds
|
|
push es
|
|
mov bp,sp
|
|
cld
|
|
|
|
; No current way to fix #GP fault: print the GP fault message, and if
|
|
; we have a debugging version dump the registers so that we can see what
|
|
; happened.
|
|
|
|
cld
|
|
push SEL_DXDATA or STD_RING
|
|
pop ds
|
|
assume ds:DGROUP
|
|
|
|
if DEBUG
|
|
DXcall TestDebugIns ;running under a debugger?
|
|
else
|
|
cmp fDebug,0 ;running under a debugger?
|
|
endif
|
|
jz noDebugger
|
|
jmp tpgp85 ;No, go trap out to debugger
|
|
noDebugger:
|
|
|
|
; We have an unrecoverable fault. Print an error message telling the
|
|
; user what has happened, and then try to quit.
|
|
|
|
mov ax,3
|
|
int 10h
|
|
|
|
push ds
|
|
mov ax,cs
|
|
mov ds,ax
|
|
assume ds:NOTHING
|
|
mov dx,offset szFaultMessage
|
|
pmdossvc 9h
|
|
|
|
pop ds
|
|
assume ds:DGROUP
|
|
|
|
; if DEBUG ;------------------------------------------------------------
|
|
|
|
; A fault with no debugger! Dump out the registers at the time of the fault.
|
|
|
|
push ds
|
|
pop es
|
|
|
|
mov di,offset DGROUP:szRegDump+3
|
|
mov ax,regAX
|
|
call Hex2Asc
|
|
add di,4
|
|
mov ax,regBX ;How is this for brute force
|
|
call Hex2Asc ; programming? :-)
|
|
add di,4
|
|
mov ax,regCX
|
|
call Hex2Asc
|
|
add di,4
|
|
mov ax,regDX
|
|
call Hex2Asc
|
|
add di,4
|
|
mov ax,regSI
|
|
call Hex2Asc
|
|
add di,4
|
|
mov ax,regDI
|
|
call Hex2Asc
|
|
add di,4
|
|
mov ax,regBP
|
|
call Hex2Asc
|
|
add di,5
|
|
mov ax,regDS
|
|
call Hex2Asc
|
|
add di,4
|
|
mov ax,regES
|
|
call Hex2Asc
|
|
add di,4
|
|
mov ax,idError
|
|
call Hex2Asc
|
|
add di,4
|
|
mov ax,regCS
|
|
call Hex2Asc
|
|
add di,4
|
|
mov ax,regIP
|
|
call Hex2Asc
|
|
add di,4
|
|
mov ax,regSS
|
|
call Hex2Asc
|
|
add di,4
|
|
mov ax,regSP
|
|
call Hex2Asc
|
|
|
|
mov dx,offset DGROUP:szRegDump
|
|
pmdossvc 9h
|
|
|
|
; endif ;DEBUG --------------------------------------------------------
|
|
|
|
; To exit, we want to make sure that the Dos Extender's child is the
|
|
; current program and then exit through DOS. This will take us out
|
|
; through the normal dos extender termination code which will clean
|
|
; up.
|
|
|
|
public PMAbort
|
|
PMAbort:
|
|
mov ds,selDgroupPM
|
|
|
|
mov bx,selPSPChild
|
|
pmdossvc 50h ;set psp function
|
|
|
|
mov fFaultAbort,01 ;set aborting flag
|
|
|
|
mov al,0FFh ;error code of FF
|
|
pmdossvc 4Ch ;and quit
|
|
|
|
int 3 ;should never get here!
|
|
|
|
tpgp85:
|
|
|
|
; We can't fix the fault, so trap out to the debugger so we can look at it.
|
|
|
|
mov ax,DS_ForcedGO ;Wdeb386 command to set a breakpoint
|
|
mov cx,word ptr regCS
|
|
|
|
cmp idCpuType,3 ;need to pass 32 bit reg to debugger?
|
|
jae debug_386
|
|
|
|
push bx ; no, we're on a 286
|
|
mov bx,word ptr regIP
|
|
int DebOut_Int
|
|
pop bx
|
|
jmp short @f
|
|
|
|
debug_386:
|
|
.386
|
|
push ebx ; yup... 32 bits it is
|
|
movzx ebx,word ptr regIP
|
|
int DebOut_Int
|
|
pop ebx
|
|
|
|
@@:
|
|
.286p
|
|
pop es ;restore regs and restart faulting
|
|
pop ds ; instruction which will trap at the
|
|
assume ds:NOTHING,es:NOTHING ; wdeb386 breakpoint
|
|
popa
|
|
|
|
ret
|
|
|
|
TrapHandler endp
|
|
|
|
; -------------------------------------------------------
|
|
; TrapInvalidOpcode
|
|
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public TrapInvalidOpcode
|
|
|
|
TrapInvalidOpcode:
|
|
|
|
Trace_Out "Invalid Opcode Fault!"
|
|
jmp TrapHandler
|
|
|
|
; -------------------------------------------------------
|
|
; TrapDoubleFault
|
|
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public TrapDoubleFault
|
|
|
|
TrapDoubleFault:
|
|
|
|
|
|
Trace_Out "Double Fault!"
|
|
jmp TrapHandler
|
|
|
|
; -------------------------------------------------------
|
|
; TrapExtensionOverrun
|
|
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public TrapExtensionOverrun
|
|
|
|
TrapExtensionOverrun:
|
|
jmp TrapHandler
|
|
|
|
; -------------------------------------------------------
|
|
; TrapInvalidTSS
|
|
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public TrapInvalidTSS
|
|
|
|
TrapInvalidTSS:
|
|
|
|
Trace_Out "Invalid TSS Fault!"
|
|
jmp TrapHandler
|
|
|
|
; -------------------------------------------------------
|
|
; TrapSegmentNotPresent
|
|
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public TrapSegmentNotPresent
|
|
|
|
TrapSegmentNotPresent:
|
|
|
|
Trace_Out "Segment Not Present Fault!"
|
|
jmp TrapHandler
|
|
|
|
; -------------------------------------------------------
|
|
; TrapStackOverrun
|
|
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public TrapStackOverrun
|
|
|
|
TrapStackOverrun:
|
|
|
|
Trace_Out "Stack Overrun Fault!"
|
|
jmp TrapHandler
|
|
|
|
; -------------------------------------------------------
|
|
; TrapPageFault
|
|
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public TrapPageFault
|
|
|
|
TrapPageFault:
|
|
|
|
Trace_Out "Page Fault!"
|
|
jmp TrapHandler
|
|
|
|
; -------------------------------------------------------
|
|
; TrapGP -- This routine handles General Protection faults.
|
|
|
|
assume ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
public TrapGP
|
|
|
|
TrapGP:
|
|
Trace_Out "GENERAL PROTECTION VIOLATION!"
|
|
jmp TrapHandler
|
|
|
|
; if DEBUG ;------------------------------------------------------------
|
|
|
|
; -------------------------------------------------------
|
|
; Hex2Asc -- convert AX to ascii and store at es:di
|
|
;
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
Hex2Asc proc near
|
|
|
|
rol ax, 4
|
|
call Hex2AscCH
|
|
rol ax, 4
|
|
call Hex2AscCH
|
|
rol ax, 4
|
|
call Hex2AscCH
|
|
rol ax, 4
|
|
call Hex2AscCH
|
|
ret
|
|
|
|
Hex2Asc endp
|
|
|
|
|
|
DXDATA segment
|
|
|
|
Hex_Char_Tab LABEL BYTE
|
|
db "0123456789ABCDEF"
|
|
|
|
DXDATA ends
|
|
|
|
assume ds:DGROUP,es:NOTHING
|
|
|
|
Hex2AscCH proc near
|
|
|
|
push ax
|
|
push bx
|
|
mov bx, ax
|
|
and bx, 1111b
|
|
mov al, Hex_Char_Tab[bx]
|
|
stosb
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
|
|
Hex2AscCH endp
|
|
|
|
; endif ;DEBUG --------------------------------------------------------
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXPMCODE ends
|
|
|
|
; -------------------------------------------------------
|
|
subttl Hardware Interrupt Support Code
|
|
page
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE segment
|
|
assume cs:DXCODE
|
|
|
|
;
|
|
; -------------------------------------------------------
|
|
subttl Utility Function Definitions
|
|
page
|
|
; -------------------------------------------------------
|
|
; UTILITY FUNCTION DEFINITIONS
|
|
; -------------------------------------------------------
|
|
;
|
|
; SaveRMIntrVectors -- This routine copies the current
|
|
; real mode interrupt vector table to the shadow
|
|
; vector table used by the interrupt reflector.
|
|
;
|
|
; Input: none
|
|
; Output: none
|
|
; Errors: none
|
|
; Uses; all registers preserved
|
|
;
|
|
; NOTE: This routine can only be called in REAL MODE.
|
|
|
|
assume ds:DGROUP,es:NOTHING,ss:NOTHING
|
|
public SaveRMIntrVectors
|
|
|
|
SaveRMIntrVectors:
|
|
push cx
|
|
push si
|
|
push di
|
|
push ds
|
|
push es
|
|
;
|
|
cld
|
|
push ds
|
|
pop es
|
|
xor cx,cx
|
|
mov si,cx
|
|
mov ds,cx
|
|
mov di,offset DGROUP:rglpfnRmISR
|
|
mov cx,2*256
|
|
rep movs word ptr [di],word ptr [si]
|
|
;
|
|
pop es
|
|
pop ds
|
|
pop di
|
|
pop si
|
|
pop cx
|
|
ret
|
|
|
|
; -------------------------------------------------------
|
|
; RestoreRMIntrVectors -- This routine copies the
|
|
; interrupt vectors from the real mode interrupt
|
|
; vector shadow table back down to the real interrupt
|
|
; vectors.
|
|
;
|
|
; Input: none
|
|
; Output: none
|
|
; Errors: none
|
|
; Uses; all registers preserved
|
|
;
|
|
; NOTE: This routine can only be called in REAL MODE.
|
|
|
|
assume ds:DGROUP,es:NOTHING,ss:NOTHING
|
|
public RestoreRMIntrVectors
|
|
|
|
RestoreRMIntrVectors:
|
|
push cx
|
|
push si
|
|
push di
|
|
push ds
|
|
push es
|
|
;
|
|
FCLI
|
|
cld
|
|
xor cx,cx
|
|
mov di,cx
|
|
mov es,cx
|
|
mov si,offset DGROUP:rglpfnRmISR
|
|
mov cx,2*256
|
|
rep movs word ptr [di],word ptr [si]
|
|
FSTI
|
|
;
|
|
pop es
|
|
pop ds
|
|
pop di
|
|
pop si
|
|
pop cx
|
|
ret
|
|
|
|
; -------------------------------------------------------
|
|
|
|
DXCODE ends
|
|
|
|
DXPMCODE segment
|
|
assume cs:DXPMCODE
|
|
|
|
public WowHwIntrEntryVector
|
|
|
|
|
|
WowHwIntrEntryVector:
|
|
irp x,<8, 9, 0ah, 0bh, 0ch, 0dh, 0eh, 0fh, 070h, 071h, 072h, 073h, 074h, 075h, 076h, 077h>
|
|
push word ptr x
|
|
jmp [WowHwIntDispatchProc]
|
|
endm
|
|
|
|
ifndef WOW
|
|
;--------------------------------------------------------
|
|
;
|
|
; Wow16HwIntrReflector -- This routine switches
|
|
; to the dosx stack and dispatches to an interrupt
|
|
; handler. If we are already using the dosx stack,
|
|
; no stack switch is performed.
|
|
;
|
|
; Input: ss:sp -> interrupt # (word)
|
|
;
|
|
assume ds:nothing,es:nothing,ss:nothing
|
|
public Wow16HwIntrReflector
|
|
Wow16HwIntrReflector proc near
|
|
;
|
|
; Get access to DXDATA, and point es:ebx at old stack
|
|
;
|
|
|
|
push ds
|
|
push es
|
|
push bx
|
|
push di
|
|
mov di,SEL_DXDATA OR STD_RING
|
|
mov ds,di
|
|
assume ds:DGROUP
|
|
mov di,ss
|
|
mov es,di
|
|
mov bx,sp
|
|
|
|
;
|
|
; Switch stacks if necessary
|
|
;
|
|
mov di,es
|
|
|
|
;;; Removing these tests because hardware interrupts were recursing
|
|
;;; and valid stack data was being overwritten because pbReflStack
|
|
;;; was no longer an accurate reflection of the state of the stack. (neilsa)
|
|
;;; cmp di,SEL_DXDATA OR STD_RING
|
|
;;; je w16sti20
|
|
|
|
ASSERT_REFLSTK_OK
|
|
mov di,SEL_DXDATA OR STD_RING
|
|
mov ss,di
|
|
assume ss:DGROUP
|
|
mov sp,pbReflStack
|
|
sub pbReflStack,CB_STKFRAME
|
|
|
|
;
|
|
; Save app ss:sp
|
|
;
|
|
w16sti20:
|
|
push es
|
|
push bx
|
|
|
|
;
|
|
; Rebuild original iret frame (for things like win87em.dll
|
|
;
|
|
push word ptr es:[bx + 14] ; iret frame flags
|
|
push word ptr es:[bx + 12] ; iret frame cs
|
|
push word ptr es:[bx + 10] ; iret frame ip
|
|
|
|
;
|
|
; Build iret frame to return to stack switcher
|
|
;
|
|
pushf
|
|
push cs
|
|
push offset w16sti40
|
|
|
|
;
|
|
; Build a frame to call the interrupt handler
|
|
;
|
|
mov di,word ptr es:[bx]+8
|
|
|
|
; Note: this magic needs to change for use with other than HW ints
|
|
sub di,8
|
|
cmp di,8
|
|
jna w16sti30
|
|
|
|
sub di,070h - 16
|
|
w16sti30:
|
|
shl di,3 ; di = di * 8 -> make di an index
|
|
push word ptr HwIntHandlers[di + 4] ; handler cs
|
|
push word ptr HwIntHandlers[di] ; handler ip
|
|
|
|
;
|
|
; restore ds, es, ebx, edi for int handler
|
|
;
|
|
push word ptr es:[bx] ; di
|
|
push word ptr es:[bx + 2] ; bx
|
|
push word ptr es:[bx + 4] ; es
|
|
push word ptr es:[bx + 6] ; ds
|
|
pop ds
|
|
assume ds:nothing
|
|
pop es
|
|
pop bx
|
|
pop di
|
|
|
|
retf
|
|
|
|
;
|
|
; Back from interrupt handler
|
|
;
|
|
w16sti40:
|
|
add sp,6 ; remove extra iret frame
|
|
FCLI
|
|
push bp
|
|
mov bp,sp
|
|
;;; cmp word ptr [bp + 4],SEL_DXDATA OR STD_RING ;removed (neilsa)
|
|
;;; je w16sti50
|
|
|
|
ASSERT_REFLSTK_OK
|
|
add pbReflStack,CB_STKFRAME
|
|
ASSERT_REFLSTK_OK
|
|
w16sti50:
|
|
push ax
|
|
push bx
|
|
push es
|
|
mov es,[bp + 4]
|
|
mov bx,[bp + 2]
|
|
mov ax,[bp - 2] ; ax
|
|
mov es:[bx],ax
|
|
mov ax,[bp - 4] ; bx
|
|
mov es:[bx + 2],ax
|
|
mov ax,[bp - 6] ; es
|
|
mov es:[bx + 4],ax
|
|
mov ax,[bp] ; bp
|
|
mov es:[bx + 6],ax
|
|
mov ax,es
|
|
mov ss,ax
|
|
mov sp,bx
|
|
assume ss:NOTHING
|
|
pop ax
|
|
pop bx
|
|
pop es
|
|
pop bp
|
|
add sp,2 ; remove stuff from stack
|
|
riret
|
|
Wow16HwIntrReflector endp
|
|
|
|
else ; wow
|
|
|
|
;*****************************************************************************
|
|
; The following two routines are the entry points for hardware interrupts.
|
|
; The monitor or the kernel may or may not have explicitly switched to the
|
|
; "locked" pm stack. These routines dispatch the interrupt, and then will
|
|
; switch stacks back if it is finally "unwound" out of all nested interrupts.
|
|
;*****************************************************************************
|
|
|
|
;--------------------------------------------------------
|
|
;
|
|
; Wow16HwIntrReflector -- This routine switches
|
|
; to the dosx stack and dispatches to an interrupt
|
|
; handler. If we are already using the dosx stack,
|
|
; no stack switch is performed.
|
|
;
|
|
; Input: ss:sp -> interrupt # (word)
|
|
;
|
|
assume ds:nothing,es:nothing,ss:nothing
|
|
public Wow16HwIntrReflector
|
|
Wow16HwIntrReflector proc near
|
|
.386p
|
|
ASSERT_CLI
|
|
;
|
|
; Get access to DXDATA, and point es:ebx at old stack
|
|
;
|
|
|
|
push ds
|
|
push es
|
|
push ebx
|
|
push eax
|
|
mov ax,SEL_DXDATA OR STD_RING
|
|
mov ds,ax
|
|
assume ds:DGROUP
|
|
mov ax,ss
|
|
mov es,ax
|
|
mov ebx,esp
|
|
lar eax,eax
|
|
test eax,(AB_BIG SHL 8)
|
|
jnz w16sti10
|
|
|
|
movzx ebx,bx
|
|
w16sti10:
|
|
push es
|
|
push ebx
|
|
|
|
;
|
|
; Rebuild original iret frame (for things like win87em.dll
|
|
;
|
|
push word ptr es:[ebx + 22] ; iret frame flags
|
|
push word ptr es:[ebx + 18] ; iret frame cs
|
|
push word ptr es:[ebx + 14] ; iret frame ip
|
|
|
|
;
|
|
; Build iret frame to return to stack switcher
|
|
;
|
|
pushf
|
|
push cs
|
|
push offset w16hwi40
|
|
|
|
;
|
|
; Build a frame to call the interrupt handler
|
|
;
|
|
movzx eax,word ptr es:[ebx]+12
|
|
|
|
DEBUG_TRACE DBGTR_HWINT, ax, 16h, 0
|
|
; Note: this magic needs to change for use with other than HW ints
|
|
sub eax,8
|
|
cmp eax,8
|
|
jna w16hwi30
|
|
sub eax,070h - 16
|
|
w16hwi30:
|
|
|
|
shl eax,3 ; ax = ax * 8 -> make ax an index
|
|
push word ptr HwIntHandlers[eax + 4] ; handler cs
|
|
push word ptr HwIntHandlers[eax] ; handler ip
|
|
|
|
;
|
|
; restore ds, es, ebx, eax for int handler
|
|
;
|
|
push dword ptr es:[ebx] ; eax
|
|
push dword ptr es:[ebx + 4] ; ebx
|
|
push word ptr es:[ebx + 8] ; es
|
|
push word ptr es:[ebx + 10] ; ds
|
|
pop ds
|
|
assume ds:nothing
|
|
pop es
|
|
pop ebx
|
|
pop eax
|
|
|
|
retf
|
|
|
|
;
|
|
; Back from interrupt handler
|
|
;
|
|
w16hwi40:
|
|
add sp,6 ; remove extra iret frame
|
|
FCLI
|
|
DEBUG_TRACE DBGTR_EXIT, 0, 16h, 0
|
|
push bp
|
|
mov bp,sp
|
|
push eax
|
|
push ebx
|
|
push es
|
|
|
|
mov ax, SEL_VDMTIB or STD_RING
|
|
mov es, ax
|
|
dec word ptr es:[VDMTIB_LockCount]
|
|
jnz short w16hwi60
|
|
|
|
mov ss, es:[VDMTIB_SaveSsSelector]
|
|
mov esp, es:[VDMTIB_SaveEsp]
|
|
assume ss:NOTHING
|
|
|
|
mov ax, SEL_DXDATA OR STD_RING ;BUGBUG pick it off the stack?
|
|
mov es, ax
|
|
|
|
mov eax, es:[bp+8]
|
|
mov ebx, es:[bp+12]
|
|
|
|
push dword ptr es:[bp+30] ;flags
|
|
push dword ptr es:[bp+26] ;cs
|
|
push dword ptr es:[bp+22] ;eip
|
|
push word ptr es:[bp]
|
|
push word ptr es:[bp+16]
|
|
push word ptr es:[bp+18]
|
|
|
|
pop ds
|
|
pop es
|
|
pop bp
|
|
jmp short w16hwi70
|
|
w16hwi60:
|
|
pop es
|
|
pop ebx
|
|
pop eax
|
|
pop bp
|
|
add esp, 20
|
|
w16hwi70:
|
|
|
|
riretd
|
|
Wow16HwIntrReflector endp
|
|
|
|
|
|
|
|
;--------------------------------------------------------
|
|
;
|
|
; Wow32HwIntrReflector -- This routine switches
|
|
; to the dosx stack and dispatches to an interrupt
|
|
; handler. If we are already using the dosx stack,
|
|
; no stack switch is performed.
|
|
;
|
|
; Input: ss:sp -> interrupt # (word)
|
|
;
|
|
assume ds:nothing,es:nothing,ss:nothing
|
|
public Wow32HwIntrReflector
|
|
Wow32HwIntrReflector proc near
|
|
|
|
;
|
|
; Get access to DXDATA, and point es:ebx at old stack
|
|
;
|
|
|
|
push ds
|
|
push es
|
|
push ebx
|
|
push eax
|
|
mov ax,SEL_DXDATA OR STD_RING
|
|
mov ds,ax
|
|
assume ds:DGROUP
|
|
mov ax,ss
|
|
mov es,ax
|
|
mov ebx,esp
|
|
lar eax,eax
|
|
test eax,(AB_BIG SHL 8)
|
|
jnz w32hwi10
|
|
|
|
movzx ebx,bx
|
|
w32hwi10:
|
|
push es
|
|
push ebx
|
|
|
|
;
|
|
; Rebuild original iret frame (for things like win87em.dll
|
|
;
|
|
push dword ptr es:[ebx + 22] ; iret frame flags
|
|
push dword ptr es:[ebx + 18] ; iret frame cs
|
|
push dword ptr es:[ebx + 14] ; iret frame ip
|
|
|
|
;
|
|
; Build iret frame to return to stack switcher
|
|
;
|
|
pushfd
|
|
push 0
|
|
push cs
|
|
push 0
|
|
push offset w32hwi40
|
|
|
|
;
|
|
; Build a frame to call the interrupt handler
|
|
;
|
|
movzx eax,es:[ebx]+12
|
|
|
|
DEBUG_TRACE DBGTR_HWINT, ax, 32h, 0
|
|
; Note: this magic needs to change for use with other than HW ints
|
|
sub eax,8
|
|
cmp eax,8
|
|
jna w32hwi30
|
|
|
|
sub eax,070h - 16
|
|
w32hwi30:
|
|
shl eax,3 ; ax = ax * 8 -> make ax an index
|
|
push dword ptr HwIntHandlers[eax + 4] ; handler cs
|
|
push dword ptr HwIntHandlers[eax] ; handler ip
|
|
|
|
;
|
|
; restore ds, es, ebx, eax for int handler
|
|
;
|
|
push dword ptr es:[ebx] ; eax
|
|
push dword ptr es:[ebx + 4] ; ebx
|
|
push word ptr es:[ebx + 8] ; es
|
|
push word ptr es:[ebx + 10] ; ds
|
|
pop ds
|
|
assume ds:nothing
|
|
pop es
|
|
pop ebx
|
|
pop eax
|
|
|
|
db 066h
|
|
retf ; far 32 bit retf
|
|
|
|
;
|
|
; Back from interrupt handler
|
|
;
|
|
w32hwi40:
|
|
add sp,12 ; remove additional iret frame
|
|
FCLI
|
|
DEBUG_TRACE DBGTR_EXIT, 0, 32h, 0
|
|
push bp
|
|
mov bp,sp
|
|
push eax
|
|
push ebx
|
|
push es
|
|
|
|
mov ax, SEL_VDMTIB or STD_RING
|
|
mov es, ax
|
|
dec word ptr es:[0] ;BUGBUG LockCount
|
|
jnz short w32hwi60
|
|
|
|
mov ss, es:[4] ;BUGBUG SaveSsSelector
|
|
mov esp, es:[10] ;BUGBUG SaveEsp
|
|
assume ss:NOTHING
|
|
|
|
mov ax, SEL_DXDATA OR STD_RING ;BUGBUG pick it off the stack?
|
|
mov es, ax
|
|
|
|
mov eax, es:[bp+8]
|
|
mov ebx, es:[bp+12]
|
|
|
|
push dword ptr es:[bp+30] ;flags
|
|
push dword ptr es:[bp+26] ;cs
|
|
push dword ptr es:[bp+22] ;eip
|
|
push word ptr es:[bp]
|
|
push word ptr es:[bp+16]
|
|
push word ptr es:[bp+18]
|
|
|
|
pop ds
|
|
pop es
|
|
pop bp
|
|
jmp short w32hwi70
|
|
w32hwi60:
|
|
pop es
|
|
pop ebx
|
|
pop eax
|
|
pop bp
|
|
add esp, 20
|
|
w32hwi70:
|
|
push ebx
|
|
mov bx,ss
|
|
lar ebx,ebx
|
|
test ebx,(AB_BIG SHL 8)
|
|
jz w32hwi90
|
|
|
|
pop ebx
|
|
riretd32
|
|
|
|
w32hwi90:
|
|
pop ebx
|
|
riretd
|
|
Wow32HwIntrReflector endp
|
|
|
|
.286p
|
|
|
|
;--------------------------------------------------------
|
|
;
|
|
; Wow16TransitionToUserMode -- This routine simulates a
|
|
; ring transition from the kernelmode dos extender
|
|
; code to the usermode dos extender code. It does this
|
|
; by restoring the user regs from the dosx stack, restoring
|
|
; user bp from user stack, and retf
|
|
;
|
|
; Inputs: ss:sp -> user ds
|
|
; user ax
|
|
; user bx
|
|
; user cx
|
|
; user sp
|
|
; user ss
|
|
; user ss:sp -> user bp
|
|
; user ip
|
|
; user cs
|
|
; Outputs: none
|
|
;
|
|
|
|
assume ds:nothing,es:nothing,ss:DGROUP
|
|
public Wow16TransitionToUserMode
|
|
Wow16TransitionToUserMode proc
|
|
|
|
pop ds
|
|
pop ax
|
|
pop bx
|
|
pop cx
|
|
mov bp,sp
|
|
.386p
|
|
lss sp,[bp]
|
|
.286p
|
|
pop bp
|
|
retf
|
|
|
|
Wow16TransitionToUserMode endp
|
|
|
|
;--------------------------------------------------------
|
|
;
|
|
; wow32TransitionToUserMode -- This routine simulates a
|
|
; ring transition from the kernelmode dos extender
|
|
; code to the usermode dos extender code. It does this
|
|
; by restoring the user regs from the dosx stack, restoring
|
|
; user bp from user stack, and retf
|
|
;
|
|
; Inputs: ss:sp -> user ds
|
|
; user ax
|
|
; user bx
|
|
; user cx
|
|
; user esp
|
|
; user ss
|
|
; user ss:sp -> user bp
|
|
; user eip
|
|
; user cs
|
|
; Outputs: none
|
|
;
|
|
|
|
assume ds:nothing,es:nothing,ss:DGROUP
|
|
public wow32TransitionToUserMode
|
|
wow32TransitionToUserMode proc
|
|
|
|
pop ds
|
|
pop ax
|
|
pop bx
|
|
pop cx
|
|
mov bp,sp
|
|
.386p
|
|
lss esp,[bp]
|
|
.286p
|
|
pop bp
|
|
db 066h ; operand override
|
|
retf
|
|
|
|
wow32TransitionToUserMode endp
|
|
|
|
;--------------------------------------------------------
|
|
;
|
|
; Wow16CopyEhStack -- build a frame on the user stack
|
|
; for dispatching an exception.
|
|
;
|
|
; Inputs: ds:bx -> exception handling stack
|
|
; Outputs: stack frames built on eh and dosx stack
|
|
;
|
|
;
|
|
assume ds:nothing,es:nothing,ss:DGROUP
|
|
public Wow16CopyEhStack
|
|
Wow16CopyEhStack proc
|
|
|
|
push si
|
|
|
|
mov cx,6
|
|
lea si,Ring0_EH_SS
|
|
ces1610:
|
|
sub bx,2
|
|
mov ax,word ptr ss:[si]
|
|
mov word ptr [bx],ax
|
|
sub si,4
|
|
loop ces1610
|
|
|
|
;
|
|
; Put address of fault handler clean up routine on stack
|
|
;
|
|
sub bx,2
|
|
mov word ptr [bx],SEL_DXPMCODE or STD_RING
|
|
sub bx,2
|
|
mov word ptr [bx],offset DXPMCODE:Wow16FaultCleanup
|
|
;
|
|
; Get return addr to exception header (used to figure out which exception)
|
|
;
|
|
add si,2
|
|
mov ax,word ptr ss:[si]
|
|
;
|
|
; Put address of fault reflector on user stack
|
|
;
|
|
sub ax,offset DXPMCODE:PMFaultEntryVector+3
|
|
mov cl,3
|
|
div cl
|
|
shl ax,3
|
|
lea bp,PmFaultVector
|
|
add bp,ax
|
|
mov ax,word ptr [bp + 4]
|
|
sub bx,2
|
|
mov word ptr [bx],ax
|
|
sub bx,2
|
|
mov ax,word ptr [bp]
|
|
mov [bx],ax
|
|
;
|
|
; Put user bp on user stack
|
|
;
|
|
mov ax,Ring0_EH_CX
|
|
sub bx,2
|
|
mov [bx],ax
|
|
|
|
;
|
|
; Push ss:sp onto current stack
|
|
;
|
|
mov ax,ds
|
|
mov Ring0_EH_BP,ax ; ss
|
|
mov Ring0_EH_CX,bx ; sp
|
|
|
|
pop si
|
|
ret
|
|
Wow16CopyEhStack endp
|
|
|
|
;--------------------------------------------------------
|
|
;
|
|
; Wow16FaultCleanup -- Removes the fault handler frame from
|
|
; the stack, and continues.
|
|
;
|
|
; Inputs: None
|
|
; Outputs: fault handler stack frame removed.
|
|
;
|
|
;
|
|
assume ds:nothing,es:nothing,ss:nothing
|
|
public Wow16FaultCleanup
|
|
Wow16FaultCleanup proc
|
|
.386p
|
|
FCLI
|
|
add sp,2 ; pop error code
|
|
push bp
|
|
mov bp,sp
|
|
push bx
|
|
push ds
|
|
push ax
|
|
|
|
mov ax,SEL_DXDATA or STD_RING ; Free EH stacklet
|
|
mov ds, ax
|
|
add ds:npEHStacklet,CB_STKFRAME
|
|
|
|
mov ax,[bp + 10]
|
|
mov ds,ax
|
|
mov bx,[bp + 8] ; ds:bx -> user stack
|
|
sub bx,2
|
|
mov ax,[bp + 6]
|
|
mov ds:[bx],ax ; push flags
|
|
sub bx,2
|
|
mov ax,[bp + 4]
|
|
mov ds:[bx],ax ; push cs
|
|
sub bx,2
|
|
mov ax,[bp + 2]
|
|
mov ds:[bx],ax ; push ip
|
|
sub bx,2
|
|
mov ax,[bp]
|
|
mov ds:[bx],ax ; push bp
|
|
mov [bp + 8],bx
|
|
pop ax
|
|
pop ds
|
|
pop bx
|
|
pop bp
|
|
|
|
add sp,6 ; point to ss:sp
|
|
mov bp,sp
|
|
|
|
lss sp,[bp]
|
|
.286p
|
|
pop bp ; restore bp
|
|
riret
|
|
Wow16FaultCleanup endp
|
|
|
|
|
|
;--------------------------------------------------------
|
|
;
|
|
; Wow32CopyEhStack -- build a frame on the user stack
|
|
; for dispatching an exception.
|
|
;
|
|
; Inputs: ds:bx -> exception handling stack
|
|
; Outputs: stack frames built on eh and dosx stack
|
|
;
|
|
;
|
|
assume ds:nothing,es:nothing,ss:DGROUP
|
|
public Wow32CopyEhStack
|
|
Wow32CopyEhStack proc
|
|
.386p
|
|
push si
|
|
push eax
|
|
|
|
mov cx,6
|
|
lea si,Ring0_EH_SS
|
|
ces3210:
|
|
sub bx,4
|
|
mov eax,dword ptr ss:[si]
|
|
mov dword ptr [bx],eax
|
|
sub si,4
|
|
loop ces3210
|
|
|
|
;
|
|
; Put address of fault handler clean up routine on stack
|
|
;
|
|
sub bx,4
|
|
mov dword ptr [bx],SEL_DXPMCODE or STD_RING
|
|
sub bx,4
|
|
mov dword ptr [bx],offset DXPMCODE:Wow32FaultCleanup
|
|
|
|
;
|
|
; Get return addr to exception header (used to figure out which exception)
|
|
;
|
|
mov ax,word ptr ss:[si + 2]
|
|
|
|
;
|
|
; Put address of fault reflector on user stack
|
|
;
|
|
sub ax,offset DXPMCODE:PMFaultEntryVector+3
|
|
mov cl,3
|
|
div cl
|
|
shl ax,3
|
|
lea bp,PmFaultVector
|
|
add bp,ax
|
|
mov ax,word ptr [bp + 4]
|
|
sub bx,4
|
|
mov word ptr [bx],ax
|
|
sub bx,4
|
|
mov eax,dword ptr [bp]
|
|
mov [bx],eax
|
|
|
|
;
|
|
; Put user bp on user stack
|
|
;
|
|
mov ax,Ring0_EH_CX
|
|
sub bx,2
|
|
mov [bx],ax
|
|
|
|
;
|
|
; Stick user ss:esp on our stack
|
|
;
|
|
mov ax,ds
|
|
mov Ring0_EH_PEC,ax
|
|
mov Ring0_EH_BP,0 ; high half esp
|
|
mov Ring0_EH_CX,bx
|
|
|
|
pop eax
|
|
pop si
|
|
ret
|
|
.286p
|
|
Wow32CopyEhStack endp
|
|
|
|
;--------------------------------------------------------
|
|
;
|
|
; wow32FaultCleanup -- Removes the fault handler frame from
|
|
; the stack, and continues.
|
|
;
|
|
; Inputs: None
|
|
; Outputs: fault handler stack frame removed.
|
|
;
|
|
;
|
|
assume ds:nothing,es:nothing,ss:nothing
|
|
public Wow32FaultCleanup
|
|
wow32FaultCleanup proc
|
|
.386p
|
|
FCLI
|
|
add esp,4 ; pop error code
|
|
push ebp
|
|
mov ebp,esp
|
|
push ebx
|
|
push ds
|
|
push eax
|
|
|
|
mov ax,SEL_DXDATA or STD_RING ; Free EH stacklet
|
|
mov ds, ax
|
|
add ds:npEHStacklet,CB_STKFRAME
|
|
|
|
movzx eax,word ptr [ebp + 20]
|
|
mov ds,ax
|
|
mov ebx,[ebp + 16] ; ds:bx -> user stack
|
|
lar eax,eax
|
|
test eax,(AB_BIG SHL 8)
|
|
jnz w32fc10
|
|
|
|
movzx ebx,bx ; high half should be zero
|
|
w32fc10:
|
|
sub ebx,4
|
|
mov eax,[ebp + 12]
|
|
mov ds:[ebx],eax ; push flags
|
|
sub ebx,4
|
|
mov eax,[ebp + 8]
|
|
mov ds:[ebx],eax ; push cs
|
|
sub ebx,4
|
|
mov eax,[ebp + 4]
|
|
mov ds:[ebx],eax ; push ip
|
|
sub ebx,4
|
|
mov eax,[ebp]
|
|
mov ds:[ebx],eax ; push bp
|
|
mov [ebp + 16],ebx ; update esp
|
|
pop eax
|
|
pop ds
|
|
pop ebx
|
|
pop ebp
|
|
|
|
add esp,12 ; point to ss:sp
|
|
mov ebp,esp
|
|
|
|
lss esp,[ebp]
|
|
pop ebp ; restore bp
|
|
push ebx
|
|
mov bx,ss
|
|
lar ebx,ebx
|
|
test ebx,(AB_BIG SHL 8)
|
|
jz w32fc20
|
|
|
|
pop ebx
|
|
riretd32
|
|
|
|
w32fc20:
|
|
pop ebx
|
|
riretd
|
|
.286p
|
|
wow32FaultCleanup endp
|
|
|
|
;--------------------------------------------------------
|
|
;
|
|
; Wow16CopyIretStack -- build a frame on the user stack
|
|
; for dispatching an exception.
|
|
;
|
|
; Inputs: none
|
|
; Outputs: stack frames built on eh and dosx stack
|
|
;
|
|
;
|
|
assume ds:nothing,es:nothing,ss:DGROUP
|
|
public Wow16CopyIretStack
|
|
Wow16CopyIretStack proc
|
|
|
|
push si
|
|
mov ax,Ring0_EH_SS
|
|
mov ds,ax
|
|
mov bx,Ring0_EH_SP
|
|
lea si,Ring0_EH_Flags
|
|
mov cx,3
|
|
cis1610:
|
|
sub bx,2
|
|
mov ax,ss:[si]
|
|
mov [bx],ax
|
|
sub si,4
|
|
loop cis1610
|
|
|
|
;
|
|
; Get the address of the interrupt handler
|
|
;
|
|
mov ax,Ring0_EH_PEC
|
|
sub ax,offset DXPMCODE:PMFaultEntryVector+3
|
|
mov cl,3
|
|
div cl ; AX = interrupt number
|
|
shl ax,3 ; AX = vector entry offset
|
|
push es
|
|
push SEL_IDT OR STD_RING
|
|
pop es
|
|
mov si,ax ; BP -> interrupt handler address
|
|
mov ax,es:[si].offDest ; AX = IP of handler
|
|
mov cx,es:[si].selDest ; CX = CS of handler
|
|
pop es
|
|
sub bx,2
|
|
mov [bx],cx ; "push" ip
|
|
sub bx,2
|
|
mov [bx],ax ; "push" cs
|
|
;
|
|
; Push user bp on user stack
|
|
;
|
|
mov ax,Ring0_EH_BP
|
|
sub bx,2
|
|
mov [bx],ax
|
|
;
|
|
; Push ss:sp onto current stack
|
|
;
|
|
mov ax,ds
|
|
mov Ring0_EH_PEC,ax ; ss
|
|
mov Ring0_EH_BP,bx ; sp
|
|
|
|
pop si
|
|
ret
|
|
Wow16CopyIretStack endp
|
|
|
|
;--------------------------------------------------------
|
|
;
|
|
; wow32copyiretStack -- build a frame on the user stack
|
|
; for dispatching an exception.
|
|
;
|
|
; Inputs: none
|
|
; Outputs: stack frames built on eh and dosx stack
|
|
;
|
|
;
|
|
assume ds:nothing,es:nothing,ss:DGROUP
|
|
public wow32copyiretStack
|
|
wow32copyiretStack proc
|
|
.386p
|
|
push si
|
|
push ebx
|
|
push eax
|
|
movzx eax,word ptr Ring0_EH_SS
|
|
mov ds,ax
|
|
mov ebx,dword ptr Ring0_EH_SP
|
|
lar eax,eax
|
|
test eax,(AB_BIG SHL 8)
|
|
jnz cis3205
|
|
|
|
movzx ebx,bx
|
|
cis3205:
|
|
lea si,Ring0_EH_Flags
|
|
mov cx,3
|
|
cis3210:
|
|
sub ebx,4
|
|
mov eax,dword ptr ss:[si]
|
|
mov [ebx],eax
|
|
sub si,4
|
|
loop cis3210
|
|
|
|
;
|
|
; Get the address of the interrupt handler
|
|
;
|
|
mov ax,Ring0_EH_PEC
|
|
sub ax,offset DXPMCODE:PMFaultEntryVector+3
|
|
mov cl,3
|
|
div cl ; AX = interrupt number
|
|
shl ax,3 ; AX = vector entry offset
|
|
push es
|
|
push SEL_IDT OR STD_RING
|
|
pop es
|
|
mov si,ax ; BP -> interrupt handler address
|
|
mov ax,es:[si].rsvdGate ; AX = IP of handler
|
|
shl eax,16
|
|
mov ax,es:[si].offDest
|
|
mov cx,es:[si].selDest ; CX = CS of handler
|
|
pop es
|
|
sub ebx,4
|
|
mov [ebx],cx ; "push" cs
|
|
sub ebx,4
|
|
mov [ebx],eax ; "push" ip
|
|
;
|
|
; Push user bp on user stack
|
|
;
|
|
mov ax,Ring0_EH_BP
|
|
sub ebx,2
|
|
mov [ebx],ax
|
|
;
|
|
; Push ss:sp onto current stack
|
|
;
|
|
mov ax,ds
|
|
mov Ring0_EH_EC,ax
|
|
mov dword ptr Ring0_EH_BP,ebx
|
|
|
|
pop eax
|
|
pop ebx
|
|
pop si
|
|
ret
|
|
.286p
|
|
wow32copyiretStack endp
|
|
|
|
|
|
;--------------------------------------------------------
|
|
;
|
|
; Wow32ReservedReflector -- This routine removes the fault
|
|
; frame from the DPMI stack, and reflects to the
|
|
; appropriate interrupt handler on the original stack
|
|
;
|
|
; Inputs: none
|
|
; Outputs: none
|
|
;
|
|
assume ds:nothing, es:nothing, ss:nothing
|
|
public Wow32ReservedReflector
|
|
Wow32ReservedReflector proc
|
|
.386p
|
|
push ds
|
|
push ebx
|
|
push eax
|
|
push edi
|
|
push ebp
|
|
mov ebp,esp
|
|
|
|
;
|
|
; Copy stack frame.
|
|
; N.B. If the interrupt occurred when we were already on the dos extender
|
|
; stack, the copy will be overlapping.
|
|
;
|
|
movzx eax,word ptr [ebp + 48] ; get ss
|
|
mov ds,ax
|
|
mov ebx,[ebp + 44] ; get esp
|
|
lar eax,eax
|
|
test eax,(AB_BIG SHL 8)
|
|
jnz w32rr10
|
|
|
|
movzx ebx,bx
|
|
w32rr10:
|
|
sub ebx,24 ; room for frame + ebp + far ret addr
|
|
mov eax,[ebp + 40] ; EFlags
|
|
mov [ebx + 20],eax ; push eflags
|
|
mov eax,[ebp + 36] ; CS
|
|
mov [ebx + 16],eax ; push cs
|
|
mov eax,[ebp + 32] ; Eip
|
|
mov [ebx + 12],eax ; push Eip
|
|
mov eax,[ebp] ; ebp
|
|
mov [ebx],eax ; push ebp
|
|
mov [ebp + 20],ebx ; save esp for lss esp
|
|
mov [ebp + 24],ds ; save ss for lss esp
|
|
;
|
|
; Get the address of the interrupt handler
|
|
;
|
|
mov ax,selDGroupPM
|
|
mov es,ax
|
|
assume es:DGROUP
|
|
mov ax,[ebp + 18]
|
|
sub ax,offset DXPMCODE:PMReservedEntryVector + 5
|
|
mov dl,5
|
|
div dl
|
|
shl ax,3
|
|
push es
|
|
push SEL_IDT OR STD_RING
|
|
pop es
|
|
mov di,ax
|
|
mov ax,es:[di].rsvdGate
|
|
shl eax,16
|
|
mov ax,es:[di].offDest
|
|
mov [ebx + 4],eax
|
|
movzx eax,word ptr es:[di].selDest
|
|
mov [ebx + 8],eax
|
|
pop es
|
|
;
|
|
; Restore Registers, switch stacks, and return
|
|
;
|
|
add esp,4 ; ebp comes off user stack
|
|
pop edi
|
|
pop eax
|
|
pop ebx
|
|
pop ds
|
|
assume ds:nothing
|
|
lss esp,[ebp + 20]
|
|
pop ebp
|
|
|
|
db 066h ; 48 bit far return
|
|
retf
|
|
.286p
|
|
Wow32ReservedReflector endp
|
|
|
|
public Wow32IntrRefl
|
|
Wow32IntrRefl label word
|
|
??intnum = 0
|
|
rept 256
|
|
push word ptr ??intnum
|
|
jmp Wow32Intr16Reflector
|
|
??intnum = ??intnum + 1
|
|
endm
|
|
;--------------------------------------------------------
|
|
;
|
|
; Wow32Intr16Reflector -- This routine reflects a 32 bit
|
|
; interrupt to a 16 bit handler. It switches to the
|
|
; dos extender stack to do so.
|
|
;
|
|
; Inputs: none
|
|
; Outputs: none
|
|
;
|
|
assume ds:nothing,es:nothing,ss:nothing
|
|
public Wow32Intr16Reflector
|
|
Wow32Intr16Reflector proc
|
|
.386p
|
|
push ebp
|
|
mov ebp,esp
|
|
push ds
|
|
push eax
|
|
push ebx
|
|
push edi
|
|
mov ax,ss
|
|
movzx eax,ax
|
|
lar eax,eax
|
|
test eax,(AB_BIG SHL 8)
|
|
jnz w32i16r10
|
|
|
|
movzx ebp,bp
|
|
w32i16r10:
|
|
|
|
;
|
|
; Get a frame on the dosx stack.
|
|
;
|
|
mov ax,selDgroupPM
|
|
mov ds,ax
|
|
assume ds:DGROUP
|
|
|
|
movzx ebx,pbReflStack
|
|
sub pbReflStack,CB_STKFRAME
|
|
|
|
;
|
|
; Build a frame on the stack
|
|
;
|
|
sub bx,30
|
|
mov eax, [ebp+6] ; eip
|
|
mov [bx+20], eax
|
|
mov eax, [ebp+10] ; cs
|
|
mov [bx+24], eax
|
|
|
|
mov [bx + 18],ss ; ss for stack switch back
|
|
mov eax,ebp
|
|
add eax,6 ; ebp, int number
|
|
mov [bx + 14],eax ; esp for stack switch back
|
|
mov ax,[ebp + 14] ; get flags
|
|
mov [bx + 12],ax
|
|
mov ax,cs
|
|
mov [bx + 10],ax
|
|
mov [bx + 8],offset DXPMCODE:w3216r30
|
|
mov eax,[ebp]
|
|
mov [bx],eax ; put ebp on other stack for pop
|
|
;
|
|
; Get handler
|
|
;
|
|
mov di,[ebp + 4] ; int number
|
|
shl di,2 ; al * 4
|
|
add di,offset DGROUP:Wow16BitHandlers
|
|
mov ax,[di]
|
|
mov [bx + 4],ax ; handler ip
|
|
mov ax,[di + 2]
|
|
mov [bx + 6],ax ; handler cs
|
|
|
|
;
|
|
; Set up for stack switch
|
|
;
|
|
push ds
|
|
push ebx
|
|
;
|
|
; Restore registers
|
|
;
|
|
mov ax,[ebp - 2]
|
|
mov ds,ax
|
|
mov eax,[ebp - 6]
|
|
mov ebx,[ebp - 10]
|
|
mov edi,[ebp - 14]
|
|
;
|
|
; Switch stacks, restore ebp, and call handler
|
|
;
|
|
lss esp,[ebp - 20]
|
|
pop ebp
|
|
DEBUG_TRACE DBGTR_ENTRY, 0, 0, 2000h
|
|
retf
|
|
;
|
|
; N.B. i31_RMCall looks on the stack to get the original user stack pointer.
|
|
; if you change the stack frame the is passed to the 16 bit int
|
|
; handlers, that WILL break.
|
|
;
|
|
|
|
w3216r30:
|
|
DEBUG_TRACE DBGTR_EXIT, 0, 0, 2000h
|
|
;
|
|
; Switch stacks, deallocate frame from dosx stack and return
|
|
;
|
|
push ebx
|
|
push eax
|
|
push ds
|
|
lds ebx,[esp+10] ;get ss:esp
|
|
mov eax,[esp+16]
|
|
mov [ebx],eax ;eip
|
|
mov eax,[esp+20]
|
|
mov [ebx+4],eax ;cs
|
|
pop ds
|
|
pop eax
|
|
pop ebx
|
|
|
|
lss esp,[esp]
|
|
push ebx
|
|
|
|
|
|
pushfd
|
|
push eax
|
|
mov ax,ss
|
|
movzx eax,ax
|
|
lar eax,eax
|
|
test eax,(AB_BIG SHL 8) ; is the stack big?
|
|
jnz w32i16r40 ; jif yes, use 32bit operations
|
|
pop eax ; restore regs
|
|
popfd
|
|
|
|
rpushfd ; save flags, set virtual int bit
|
|
pop ebx
|
|
push ebp
|
|
movzx ebp, sp
|
|
mov [ebp + 16],ebx ; put flags on iret frame
|
|
pop ebp
|
|
push ds
|
|
mov bx,selDgroupPM
|
|
mov ds,bx
|
|
add pbReflStack,CB_STKFRAME
|
|
pop ds
|
|
pop ebx
|
|
riretd
|
|
|
|
w32i16r40: ; stack is big
|
|
pop eax ; restore regs
|
|
popfd
|
|
|
|
rpushfd32
|
|
pop ebx
|
|
mov [esp + 12],ebx
|
|
push ds
|
|
mov bx,selDgroupPM
|
|
mov ds,bx
|
|
add pbReflStack,CB_STKFRAME
|
|
pop ds
|
|
pop ebx
|
|
riretd32
|
|
|
|
.286p
|
|
Wow32Intr16Reflector endp
|
|
ENDIF
|
|
DXPMCODE ends
|
|
;
|
|
;****************************************************************
|
|
end
|