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_x86 include vdmtib.inc endif .list include intmac.inc include stackchk.inc include bop.inc include dpmi.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 extrn DpmiFlags:WORD ; ; 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 dd 0 ; other half 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. FltRtn macro off dw DXPMCODE:off dw 0 dw SEL_DXPMCODE or STD_RING dw 0 endm public PMFaultVector align 4 PMFaultVector label DWORD FltRtn PMFaultEntryVector+5*0h ; int 0 FltRtn PMFaultEntryVector+5*1h ; int 1 FltRtn PMFaultEntryVector+5*2h ; int 2 FltRtn PMFaultEntryVector+5*3h ; int 3 FltRtn PMFaultEntryVector+5*4h ; int 4 FltRtn PMFaultEntryVector+5*5h ; int 5 FltRtn PMFaultEntryVector+5*6h ; int 6 FltRtn PMFaultEntryVector+5*7h ; int 7 FltRtn PMFaultEntryVector+5*8h ; int 8 FltRtn PMFaultEntryVector+5*9h ; int 9 FltRtn PMFaultEntryVector+5*0Ah ; int a FltRtn PMFaultEntryVector+5*0Bh ; int b FltRtn PMFaultEntryVector+5*0Ch ; int c FltRtn PMFaultEntryVector+5*0Dh ; int d FltRtn PMFaultEntryVector+5*0Eh ; int e FltRtn PMFaultEntryVector+5*0Fh ; int f FltRtn PMFaultEntryVector+5*10h ; int 10h FltRtn PMFaultEntryVector+5*11h ; int 11h FltRtn PMFaultEntryVector+5*12h ; int 12h FltRtn PMFaultEntryVector+5*13h ; int 13h FltRtn PMFaultEntryVector+5*14h ; int 14h FltRtn PMFaultEntryVector+5*15h ; int 15h FltRtn PMFaultEntryVector+5*16h ; int 16h FltRtn PMFaultEntryVector+5*17h ; int 17h FltRtn PMFaultEntryVector+5*18h ; int 18h FltRtn PMFaultEntryVector+5*19h ; int 19h FltRtn PMFaultEntryVector+5*1Ah ; int 1ah FltRtn PMFaultEntryVector+5*1Bh ; int 1bh FltRtn PMFaultEntryVector+5*1Ch ; int 1ch FltRtn PMFaultEntryVector+5*1Dh ; int 1Dh FltRtn PMFaultEntryVector+5*1Eh ; int 1Eh FltRtn PMFaultEntryVector+5*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 public Wow16BitHandlers WowTransitionToUserMode dw offset DXPMCODE:Wow16TransitionToUserMode Wow16BitHandlers dw 256 dup (0,0) ENDIF 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 Ring0_EH_EIP dw ? ; high half eip Ring0_EH_CS dw ? ; interrupted code CS dw ? ; high half of cs Ring0_EH_Flags dw ? ; interrupted code flags Ring0_EH_EFlags dw ? ; high half of flags Ring0_EH_SP dw ? ; interrupted code SP Rin0_EH_ESP dw ? ; high half of esp Ring0_EH_SS dw ? ; interrupted code SS dw ? ; high half of ss rgw0Stack label word dw 64 dup (?) ; stack for switching to ring0 public ResetStack ResetStack label word ifdef WOW_x86 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 extrn selDgroupPM:WORD extrn segDXCodePM:WORD extrn szFaultMessage:BYTE extrn szRing0FaultMessage:BYTE extrn RZCall:NEAR IFNDEF ROM extrn segDXDataPM:WORD 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 StartFaultBopTable macro ?fault = 0 endm FaultBop macro DPMIBOP DpmiUnhandledException db ?fault ?fault = ?fault+1 endm public PMFaultEntryVector ; ------------------------------------------------------- ; PMFaultEntryVector -- This table contains a vector of ; near jump instructions to the protected mode fault ; analyzer. ; PMFaultEntryVector: StartFaultBopTable rept 32 FaultBop endm assume ds:nothing,es:nothing,ss:nothing public PMFaultHandlerIRET PMFaultHandlerIRET: DPMIBOP FaultHandlerIret public PMFaultHandlerIRETD PMFaultHandlerIRETD: DPMIBOP FaultHandlerIretd public PMIntHandlerIRET PMIntHandlerIRET: DPMIBOP IntHandlerIret public PMIntHandlerIRETD PMIntHandlerIRETD: DPMIBOP IntHandlerIretd public PMDosxIret PMDosxIret: iret public PMDosxIretd PMDosxIretd: db 66h iret ; ; ------------------------------------------------------- ; 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 test DpmiFlags,DPMI_32BIT jnz rmrf_32 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 shl bx,3 mov es,selIDT 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 .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 ; 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 .386p movzx esp,word ptr pmusrsp .286p 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 .386p test DpmiFlags,word ptr DPMI_32BIT jz ri2410 pushfd push 0 push cs push 0 push offset rm24ret jmp ri2420 .286p 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 if 0 ;; ifndef WOW_x86 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 .386p movzx esp,pbReflStack .286p 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 ; ------------------------------------------------------- ; ; ------------------------------------------------------- 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 IFDEF WOW ;-------------------------------------------------------- ; ; 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 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