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, 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