summaryrefslogtreecommitdiffstats
path: root/board/MAI/bios_emulator/scitech/src/pm/dos/_pmdos.asm
diff options
context:
space:
mode:
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/pm/dos/_pmdos.asm')
-rw-r--r--board/MAI/bios_emulator/scitech/src/pm/dos/_pmdos.asm1105
1 files changed, 1105 insertions, 0 deletions
diff --git a/board/MAI/bios_emulator/scitech/src/pm/dos/_pmdos.asm b/board/MAI/bios_emulator/scitech/src/pm/dos/_pmdos.asm
new file mode 100644
index 0000000000..5c741f346c
--- /dev/null
+++ b/board/MAI/bios_emulator/scitech/src/pm/dos/_pmdos.asm
@@ -0,0 +1,1105 @@
+;****************************************************************************
+;*
+;* SciTech OS Portability Manager Library
+;*
+;* ========================================================================
+;*
+;* The contents of this file are subject to the SciTech MGL Public
+;* License Version 1.0 (the "License"); you may not use this file
+;* except in compliance with the License. You may obtain a copy of
+;* the License at http://www.scitechsoft.com/mgl-license.txt
+;*
+;* Software distributed under the License is distributed on an
+;* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+;* implied. See the License for the specific language governing
+;* rights and limitations under the License.
+;*
+;* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+;*
+;* The Initial Developer of the Original Code is SciTech Software, Inc.
+;* All Rights Reserved.
+;*
+;* ========================================================================
+;*
+;* Language: 80386 Assembler, TASM 4.0 or NASM
+;* Environment: IBM PC Real mode and 16/32 bit protected mode
+;*
+;* Description: Low level assembly support for the PM library specific to
+;* MSDOS interrupt handling.
+;*
+;****************************************************************************
+
+ IDEAL
+
+include "scitech.mac" ; Memory model macros
+
+header _pmdos ; Set up memory model
+
+; Define the size of our local stacks. For real mode code they cant be
+; that big, but for 32 bit protected mode code we can make them nice and
+; large so that complex C functions can be used.
+
+ifdef flatmodel
+MOUSE_STACK EQU 4096
+TIMER_STACK EQU 4096
+KEY_STACK EQU 1024
+INT10_STACK EQU 1024
+IRQ_STACK EQU 1024
+else
+MOUSE_STACK EQU 1024
+TIMER_STACK EQU 512
+KEY_STACK EQU 256
+INT10_STACK EQU 256
+IRQ_STACK EQU 256
+endif
+
+ifdef USE_NASM
+
+; Macro to load DS and ES registers with correct value.
+
+%imacro LOAD_DS 0
+%ifdef flatmodel
+ mov ds,[cs:_PM_savedDS]
+ mov es,[cs:_PM_savedDS]
+%else
+ push ax
+ mov ax,_DATA
+ mov ds,ax
+ pop ax
+%endif
+%endmacro
+
+; Note that interrupts we disable interrupts during the following stack
+; %imacro for correct operation, but we do not enable them again. Normally
+; these %imacros are used within interrupt handlers so interrupts should
+; already be off. We turn them back on explicitly later if the user code
+; needs them to be back on.
+
+; Macro to switch to a new local stack.
+
+%imacro NEWSTK 1
+ cli
+ mov [seg_%1],ss
+ mov [ptr_%1],_sp
+ mov [TempSeg],ds
+ mov ss,[TempSeg]
+ mov _sp,offset %1
+%endmacro
+
+; %imacro to switch back to the old stack.
+
+%imacro RESTSTK 1
+ cli
+ mov ss,[seg_%1]
+ mov _sp,[ptr_%1]
+%endmacro
+
+; %imacro to swap the current stack with the one saved away.
+
+%imacro SWAPSTK 1
+ cli
+ mov ax,ss
+ xchg ax,[seg_%1]
+ mov ss,ax
+ xchg _sp,[ptr_%1]
+%endmacro
+
+else
+
+; Macro to load DS and ES registers with correct value.
+
+MACRO LOAD_DS
+ifdef flatmodel
+ mov ds,[cs:_PM_savedDS]
+ mov es,[cs:_PM_savedDS]
+else
+ push ax
+ mov ax,_DATA
+ mov ds,ax
+ pop ax
+endif
+ENDM
+
+; Note that interrupts we disable interrupts during the following stack
+; macro for correct operation, but we do not enable them again. Normally
+; these macros are used within interrupt handlers so interrupts should
+; already be off. We turn them back on explicitly later if the user code
+; needs them to be back on.
+
+; Macro to switch to a new local stack.
+
+MACRO NEWSTK stkname
+ cli
+ mov [seg_&stkname&],ss
+ mov [ptr_&stkname&],_sp
+ mov [TempSeg],ds
+ mov ss,[TempSeg]
+ mov _sp,offset stkname
+ENDM
+
+; Macro to switch back to the old stack.
+
+MACRO RESTSTK stkname
+ cli
+ mov ss,[seg_&stkname&]
+ mov _sp,[ptr_&stkname&]
+ENDM
+
+; Macro to swap the current stack with the one saved away.
+
+MACRO SWAPSTK stkname
+ cli
+ mov ax,ss
+ xchg ax,[seg_&stkname&]
+ mov ss,ax
+ xchg _sp,[ptr_&stkname&]
+ENDM
+
+endif
+
+begdataseg _pmdos
+
+ifdef flatmodel
+ cextern _PM_savedDS,USHORT
+endif
+ cextern _PM_critHandler,CPTR
+ cextern _PM_breakHandler,CPTR
+ cextern _PM_timerHandler,CPTR
+ cextern _PM_rtcHandler,CPTR
+ cextern _PM_keyHandler,CPTR
+ cextern _PM_key15Handler,CPTR
+ cextern _PM_mouseHandler,CPTR
+ cextern _PM_int10Handler,CPTR
+
+ cextern _PM_ctrlCPtr,DPTR
+ cextern _PM_ctrlBPtr,DPTR
+ cextern _PM_critPtr,DPTR
+
+ cextern _PM_prevTimer,FCPTR
+ cextern _PM_prevRTC,FCPTR
+ cextern _PM_prevKey,FCPTR
+ cextern _PM_prevKey15,FCPTR
+ cextern _PM_prevBreak,FCPTR
+ cextern _PM_prevCtrlC,FCPTR
+ cextern _PM_prevCritical,FCPTR
+ cextern _PM_prevRealTimer,ULONG
+ cextern _PM_prevRealRTC,ULONG
+ cextern _PM_prevRealKey,ULONG
+ cextern _PM_prevRealKey15,ULONG
+ cextern _PM_prevRealInt10,ULONG
+
+cpublic _PM_pmdosDataStart
+
+; Allocate space for all of the local stacks that we need. These stacks
+; are not very large, but should be large enough for most purposes
+; (generally you want to handle these interrupts quickly, simply storing
+; the information for later and then returning). If you need bigger
+; stacks then change the appropriate value in here.
+
+ ALIGN 4
+ dclb MOUSE_STACK ; Space for local stack (small)
+MsStack: ; Stack starts at end!
+ptr_MsStack DUINT 0 ; Place to store old stack offset
+seg_MsStack dw 0 ; Place to store old stack segment
+
+ ALIGN 4
+ dclb INT10_STACK ; Space for local stack (small)
+Int10Stack: ; Stack starts at end!
+ptr_Int10Stack DUINT 0 ; Place to store old stack offset
+seg_Int10Stack dw 0 ; Place to store old stack segment
+
+ ALIGN 4
+ dclb TIMER_STACK ; Space for local stack (small)
+TmStack: ; Stack starts at end!
+ptr_TmStack DUINT 0 ; Place to store old stack offset
+seg_TmStack dw 0 ; Place to store old stack segment
+
+ ALIGN 4
+ dclb TIMER_STACK ; Space for local stack (small)
+RtcStack: ; Stack starts at end!
+ptr_RtcStack DUINT 0 ; Place to store old stack offset
+seg_RtcStack dw 0 ; Place to store old stack segment
+RtcInside dw 0 ; Are we still handling current interrupt
+
+ ALIGN 4
+ dclb KEY_STACK ; Space for local stack (small)
+KyStack: ; Stack starts at end!
+ptr_KyStack DUINT 0 ; Place to store old stack offset
+seg_KyStack dw 0 ; Place to store old stack segment
+KyInside dw 0 ; Are we still handling current interrupt
+
+ ALIGN 4
+ dclb KEY_STACK ; Space for local stack (small)
+Ky15Stack: ; Stack starts at end!
+ptr_Ky15Stack DUINT 0 ; Place to store old stack offset
+seg_Ky15Stack dw 0 ; Place to store old stack segment
+
+TempSeg dw 0 ; Place to store stack segment
+
+cpublic _PM_pmdosDataEnd
+
+enddataseg _pmdos
+
+begcodeseg _pmdos ; Start of code segment
+
+cpublic _PM_pmdosCodeStart
+
+;----------------------------------------------------------------------------
+; PM_mouseISR - Mouse interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Interrupt subroutine called by the mouse driver upon interrupts, to
+; dispatch control to high level C based subroutines. Interrupts are on
+; when we call the user code.
+;
+; It is _extremely_ important to save the state of the extended registers
+; as these may well be trashed by the routines called from here and not
+; restored correctly by the mouse interface module.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. For mouse handlers this is not a
+; problem, as the mouse driver arbitrates calls to the user mouse
+; handler for us.
+;
+; Entry: AX - Condition mask giving reason for call
+; BX - Mouse button state
+; CX - Horizontal cursor coordinate
+; DX - Vertical cursor coordinate
+; SI - Horizontal mickey value
+; DI - Vertical mickey value
+;
+;----------------------------------------------------------------------------
+ifdef DJGPP
+cprocstart _PM_mouseISR
+else
+cprocfar _PM_mouseISR
+endif
+
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+
+ LOAD_DS ; Load DS register
+ NEWSTK MsStack ; Switch to local stack
+
+; Call the installed high level C code routine
+
+ clrhi dx ; Clear out high order values
+ clrhi cx
+ clrhi bx
+ clrhi ax
+ sgnhi si
+ sgnhi di
+
+ push _di
+ push _si
+ push _dx
+ push _cx
+ push _bx
+ push _ax
+ sti ; Enable interrupts
+ call [CPTR _PM_mouseHandler]
+ _add sp,12,24
+
+ RESTSTK MsStack ; Restore previous stack
+
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ ret ; We are done!!
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_timerISR - Timer interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the timer interrupt, to dispatch control
+; to high level C based subroutines. We save the state of all registers
+; in this routine, and switch to a local stack. Interrupts are *off*
+; when we call the user code.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. Make sure your C code executes as
+; quickly as possible, since a timer overrun will simply hang the
+; system.
+;----------------------------------------------------------------------------
+cprocfar _PM_timerISR
+
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+
+ LOAD_DS ; Load DS register
+
+ NEWSTK TmStack ; Switch to local stack
+ call [CPTR _PM_timerHandler]
+ RESTSTK TmStack ; Restore previous stack
+
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_chainPrevTimer - Chain to previous timer interrupt and return
+;----------------------------------------------------------------------------
+; Chains to the previous timer interrupt routine and returns control
+; back to the high level interrupt handler.
+;----------------------------------------------------------------------------
+cprocstart PM_chainPrevTimer
+
+ifdef TNT
+ push eax
+ push ebx
+ push ecx
+ pushfd ; Push flags on stack to simulate interrupt
+ mov ax,250Eh ; Call real mode procedure function
+ mov ebx,[_PM_prevRealTimer]
+ mov ecx,1 ; Copy real mode flags to real mode stack
+ int 21h ; Call the real mode code
+ popfd
+ pop ecx
+ pop ebx
+ pop eax
+ ret
+else
+ SWAPSTK TmStack ; Swap back to previous stack
+ pushf ; Save state of interrupt flag
+ pushf ; Push flags on stack to simulate interrupt
+ifdef USE_NASM
+ call far dword [_PM_prevTimer]
+else
+ call [_PM_prevTimer]
+endif
+ popf ; Restore state of interrupt flag
+ SWAPSTK TmStack ; Swap back to C stack again
+ ret
+endif
+
+cprocend
+
+; Macro to delay briefly to ensure that enough time has elapsed between
+; successive I/O accesses so that the device being accessed can respond
+; to both accesses even on a very fast PC.
+
+ifdef USE_NASM
+%macro DELAY 0
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+%endmacro
+%macro IODELAYN 1
+%rep %1
+ DELAY
+%endrep
+%endmacro
+else
+macro DELAY
+ jmp short $+2
+ jmp short $+2
+ jmp short $+2
+endm
+macro IODELAYN N
+ rept N
+ DELAY
+ endm
+endm
+endif
+
+;----------------------------------------------------------------------------
+; PM_rtcISR - Real time clock interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the timer interrupt, to dispatch control
+; to high level C based subroutines. We save the state of all registers
+; in this routine, and switch to a local stack. Interrupts are *off*
+; when we call the user code.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. Make sure your C code executes as
+; quickly as possible, since a timer overrun will simply hang the
+; system.
+;----------------------------------------------------------------------------
+cprocfar _PM_rtcISR
+
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+
+; Clear priority interrupt controller and re-enable interrupts so we
+; dont lock things up for long.
+
+ mov al,20h
+ out 0A0h,al
+ out 020h,al
+
+; Clear real-time clock timeout
+
+ in al,70h ; Read CMOS index register
+ push _ax ; and save for later
+ IODELAYN 3
+ mov al,0Ch
+ out 70h,al
+ IODELAYN 5
+ in al,71h
+
+; Call the C interrupt handler function
+
+ LOAD_DS ; Load DS register
+ cmp [BYTE RtcInside],1 ; Check for mutual exclusion
+ je @@Exit
+ mov [BYTE RtcInside],1
+ NEWSTK RtcStack ; Switch to local stack
+ sti ; Re-enable interrupts
+ call [CPTR _PM_rtcHandler]
+ RESTSTK RtcStack ; Restore previous stack
+ mov [BYTE RtcInside],0
+
+@@Exit: pop _ax
+ out 70h,al ; Restore CMOS index register
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+cprocend
+
+ifdef flatmodel
+;----------------------------------------------------------------------------
+; PM_irqISRTemplate - Hardware interrupt handler IRQ template
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for any interrupt, to dispatch control
+; to high level C based subroutines. We save the state of all registers
+; in this routine, and switch to a local stack. Interrupts are *off*
+; when we call the user code.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. Make sure your C code executes as
+; quickly as possible.
+;----------------------------------------------------------------------------
+cprocfar _PM_irqISRTemplate
+
+ push ebx
+ mov ebx,0 ; Relocation adjustment factor
+ jmp __IRQEntry
+
+; Global variables stored in the IRQ thunk code segment
+
+_CHandler dd 0 ; Pointer to C interrupt handler
+_PrevIRQ dd 0 ; Previous IRQ handler
+ dd 0
+_IRQ dd 0 ; IRQ we are hooked for
+ptr_IRQStack DUINT 0 ; Place to store old stack offset
+seg_IRQStack dw 0 ; Place to store old stack segment
+_Inside db 0 ; Mutual exclusion flag
+ ALIGN 4
+ dclb IRQ_STACK ; Space for local stack
+_IRQStack: ; Stack starts at end!
+
+; Check for and reject spurious IRQ 7 signals
+
+__IRQEntry:
+ cmp [BYTE cs:ebx+_IRQ],7 ; Spurious IRQs occur only on IRQ 7
+ jmp @@ValidIRQ
+ push eax
+ mov al,1011b ; OCW3: read ISR
+ out 20h,al ; (Intel Peripheral Components, 1991,
+ in al,20h ; p. 3-188)
+ shl al,1 ; Set C = bit 7 (IRQ 7) of ISR register
+ pop eax
+ jc @@ValidIRQ
+ iret ; Return from interrupt
+
+; Save all registers for duration of IRQ handler
+
+@@ValidIRQ:
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+ LOAD_DS ; Load DS register
+
+; Send an EOI to the PIC
+
+ mov al,20h ; Send EOI to PIC
+ cmp [BYTE ebx+_IRQ],8 ; Clear PIC1 first if IRQ >= 8
+ jb @@1
+ out 0A0h,al
+@@1: out 20h,al
+
+; Check for mutual exclusion
+
+ cmp [BYTE ebx+_Inside],1
+ je @@ChainOldHandler
+ mov [BYTE ebx+_Inside],1
+
+; Call the C interrupt handler function
+
+ mov [ebx+seg_IRQStack],ss ; Switch to local stack
+ mov [ebx+ptr_IRQStack],esp
+ mov [TempSeg],ds
+ mov ss,[TempSeg]
+ lea esp,[ebx+_IRQStack]
+ sti ; Re-enable interrupts
+ push ebx
+ call [DWORD ebx+_CHandler]
+ pop ebx
+ cli
+ mov ss,[ebx+seg_IRQStack] ; Restore previous stack
+ mov esp,[ebx+ptr_IRQStack]
+ or eax,eax
+ jz @@ChainOldHandler ; Chain if not handled for shared IRQ
+
+@@Exit: mov [BYTE ebx+_Inside],0
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ pop ebx
+ iret ; Return from interrupt
+
+@@ChainOldHandler:
+ cmp [DWORD ebx+_PrevIRQ],0
+ jz @@Exit
+ mov [BYTE ebx+_Inside],0
+ mov eax,[DWORD ebx+_PrevIRQ]
+ mov ebx,[DWORD ebx+_PrevIRQ+4]
+ mov [DWORD _PrevIRQ],eax
+ mov [DWORD _PrevIRQ+4],ebx
+ popad ; Restore all extended registers
+ pop es
+ pop ds
+ pop ebx
+ jmp [cs:_PrevIRQ] ; Chain to previous IRQ handler
+
+cprocend
+cpublic _PM_irqISRTemplateEnd
+endif
+
+;----------------------------------------------------------------------------
+; PM_keyISR - keyboard interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the keyboard interrupt, to dispatch control
+; to high level C based subroutines. We save the state of all registers
+; in this routine, and switch to a local stack. Interrupts are *off*
+; when we call the user code.
+;
+; NOTE: This routine switches to a local stack before calling any C code,
+; and hence is _not_ re-entrant. However we ensure within this routine
+; mutual exclusion to the keyboard handling routine.
+;----------------------------------------------------------------------------
+cprocfar _PM_keyISR
+
+ push ds ; Save value of DS
+ push es
+ pushad ; Save _all_ extended registers
+ cld ; Clear direction flag
+
+ LOAD_DS ; Load DS register
+
+ cmp [BYTE KyInside],1 ; Check for mutual exclusion
+ je @@Reissued
+
+ mov [BYTE KyInside],1
+ NEWSTK KyStack ; Switch to local stack
+ call [CPTR _PM_keyHandler] ; Call C code
+ RESTSTK KyStack ; Restore previous stack
+ mov [BYTE KyInside],0
+
+@@Exit: popad ; Restore all extended registers
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+; When the BIOS keyboard handler needs to change the SHIFT status lights
+; on the keyboard, in the process of doing this the keyboard controller
+; re-issues another interrupt, while the current handler is still executing.
+; If we recieve another interrupt while still handling the current one,
+; then simply chain directly to the previous handler.
+;
+; Note that for most DOS extenders, the real mode interrupt handler that we
+; install takes care of this for us.
+
+@@Reissued:
+ifdef TNT
+ push eax
+ push ebx
+ push ecx
+ pushfd ; Push flags on stack to simulate interrupt
+ mov ax,250Eh ; Call real mode procedure function
+ mov ebx,[_PM_prevRealKey]
+ mov ecx,1 ; Copy real mode flags to real mode stack
+ int 21h ; Call the real mode code
+ popfd
+ pop ecx
+ pop ebx
+ pop eax
+else
+ pushf
+ifdef USE_NASM
+ call far dword [_PM_prevKey]
+else
+ call [_PM_prevKey]
+endif
+endif
+ jmp @@Exit
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_chainPrevkey - Chain to previous key interrupt and return
+;----------------------------------------------------------------------------
+; Chains to the previous key interrupt routine and returns control
+; back to the high level interrupt handler.
+;----------------------------------------------------------------------------
+cprocstart PM_chainPrevKey
+
+ifdef TNT
+ push eax
+ push ebx
+ push ecx
+ pushfd ; Push flags on stack to simulate interrupt
+ mov ax,250Eh ; Call real mode procedure function
+ mov ebx,[_PM_prevRealKey]
+ mov ecx,1 ; Copy real mode flags to real mode stack
+ int 21h ; Call the real mode code
+ popfd
+ pop ecx
+ pop ebx
+ pop eax
+ ret
+else
+
+; YIKES! For some strange reason, when execution returns from the
+; previous keyboard handler, interrupts are re-enabled!! Since we expect
+; interrupts to remain off during the duration of our handler, this can
+; cause havoc. However our stack macros always turn off interrupts, so they
+; will be off when we exit this routine. Obviously there is a tiny weeny
+; window when interrupts will be enabled, but there is nothing we can
+; do about this.
+
+ SWAPSTK KyStack ; Swap back to previous stack
+ pushf ; Push flags on stack to simulate interrupt
+ifdef USE_NASM
+ call far dword [_PM_prevKey]
+else
+ call [_PM_prevKey]
+endif
+ SWAPSTK KyStack ; Swap back to C stack again
+ ret
+endif
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_key15ISR - Int 15h keyboard interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; This routine gets called if we have been called to handle the Int 15h
+; keyboard interrupt callout from real mode.
+;
+; Entry: AX - Hardware scan code to process
+; Exit: AX - Hardware scan code to process (0 to ignore)
+;----------------------------------------------------------------------------
+cprocfar _PM_key15ISR
+
+ push ds
+ push es
+ LOAD_DS
+ cmp ah,4Fh
+ jnz @@NotOurs ; Quit if not keyboard callout
+
+ pushad
+ cld ; Clear direction flag
+ xor ah,ah ; AX := scan code
+ NEWSTK Ky15Stack ; Switch to local stack
+ push _ax
+ call [CPTR _PM_key15Handler] ; Call C code
+ _add sp,2,4
+ RESTSTK Ky15Stack ; Restore previous stack
+ test ax,ax
+ jz @@1
+ stc ; Set carry to process as normal
+ jmp @@2
+@@1: clc ; Clear carry to ignore scan code
+@@2: popad
+ jmp @@Exit ; We are done
+
+@@NotOurs:
+ifdef TNT
+ push eax
+ push ebx
+ push ecx
+ pushfd ; Push flags on stack to simulate interrupt
+ mov ax,250Eh ; Call real mode procedure function
+ mov ebx,[_PM_prevRealKey15]
+ mov ecx,1 ; Copy real mode flags to real mode stack
+ int 21h ; Call the real mode code
+ popfd
+ pop ecx
+ pop ebx
+ pop eax
+else
+ pushf
+ifdef USE_NASM
+ call far dword [_PM_prevKey15]
+else
+ call [_PM_prevKey15]
+endif
+endif
+@@Exit: pop es
+ pop ds
+ifdef flatmodel
+ retf 4
+else
+ retf 2
+endif
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_breakISR - Control Break interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the Ctrl-Break interrupt. We simply set
+; the Ctrl-Break flag to a 1 and leave (note that this is accessed through
+; a far pointer, as it may well be located in conventional memory).
+;----------------------------------------------------------------------------
+cprocfar _PM_breakISR
+
+ sti
+ push ds ; Save value of DS
+ push es
+ push _bx
+
+ LOAD_DS ; Load DS register
+ifdef flatmodel
+ mov ebx,[_PM_ctrlBPtr]
+else
+ les bx,[_PM_ctrlBPtr]
+endif
+ mov [UINT _ES _bx],1
+
+; Run alternate break handler code if installed
+
+ cmp [CPTR _PM_breakHandler],0
+ je @@Exit
+
+ pushad
+ mov _ax,1
+ push _ax
+ call [CPTR _PM_breakHandler] ; Call C code
+ pop _ax
+ popad
+
+@@Exit: pop _bx
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_ctrlBreakHit(int clearFlag)
+;----------------------------------------------------------------------------
+; Returns the current state of the Ctrl-Break flag and possibly clears it.
+;----------------------------------------------------------------------------
+cprocstart PM_ctrlBreakHit
+
+ ARG clearFlag:UINT
+
+ enter_c
+ pushf ; Save interrupt status
+ push es
+ifdef flatmodel
+ mov ebx,[_PM_ctrlBPtr]
+else
+ les bx,[_PM_ctrlBPtr]
+endif
+ cli ; No interrupts thanks!
+ mov _ax,[_ES _bx]
+ test [BYTE clearFlag],1
+ jz @@Done
+ mov [UINT _ES _bx],0
+
+@@Done: pop es
+ popf ; Restore interrupt status
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_ctrlCISR - Control Break interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Hardware interrupt handler for the Ctrl-C interrupt. We simply set
+; the Ctrl-C flag to a 1 and leave (note that this is accessed through
+; a far pointer, as it may well be located in conventional memory).
+;----------------------------------------------------------------------------
+cprocfar _PM_ctrlCISR
+
+ sti
+ push ds ; Save value of DS
+ push es
+ push _bx
+
+ LOAD_DS ; Load DS register
+ifdef flatmodel
+ mov ebx,[_PM_ctrlCPtr]
+else
+ les bx,[_PM_ctrlCPtr]
+endif
+ mov [UINT _ES _bx],1
+
+; Run alternate break handler code if installed
+
+ cmp [CPTR _PM_breakHandler],0
+ je @@Exit
+
+ pushad
+ mov _ax,0
+ push _ax
+ call [CPTR _PM_breakHandler] ; Call C code
+ pop _ax
+ popad
+
+@@Exit: pop _bx
+ pop es
+ pop ds
+ iret ; Return from interrupt
+ iretd
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_ctrlCHit(int clearFlag)
+;----------------------------------------------------------------------------
+; Returns the current state of the Ctrl-C flag and possibly clears it.
+;----------------------------------------------------------------------------
+cprocstart PM_ctrlCHit
+
+ ARG clearFlag:UINT
+
+ enter_c
+ pushf ; Save interrupt status
+ push es
+ifdef flatmodel
+ mov ebx,[_PM_ctrlCPtr]
+else
+ les bx,[_PM_ctrlCPtr]
+endif
+ cli ; No interrupts thanks!
+ mov _ax,[_ES _bx]
+ test [BYTE clearFlag],1
+ jz @@Done
+ mov [UINT _ES _bx],0
+
+@@Done:
+ pop es
+ popf ; Restore interrupt status
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; PM_criticalISR - Control Error handler interrupt subroutine dispatcher
+;----------------------------------------------------------------------------
+; Interrupt handler for the MSDOS Critical Error interrupt, to dispatch
+; control to high level C based subroutines. We save the state of all
+; registers in this routine, and switch to a local stack. We also pass
+; the values of the AX and DI registers to the as pointers, so that the
+; values can be modified before returning to MSDOS.
+;----------------------------------------------------------------------------
+cprocfar _PM_criticalISR
+
+ sti
+ push ds ; Save value of DS
+ push es
+ push _bx ; Save register values changed
+ cld ; Clear direction flag
+
+ LOAD_DS ; Load DS register
+ifdef flatmodel
+ mov ebx,[_PM_critPtr]
+else
+ les bx,[_PM_critPtr]
+endif
+ mov [_ES _bx],ax
+ mov [_ES _bx+2],di
+
+; Run alternate critical handler code if installed
+
+ cmp [CPTR _PM_critHandler],0
+ je @@NoAltHandler
+
+ pushad
+ push _di
+ push _ax
+ call [CPTR _PM_critHandler] ; Call C code
+ _add sp,4,8
+ popad
+
+ pop _bx
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+@@NoAltHandler:
+ mov ax,3 ; Tell MSDOS to fail the operation
+ pop _bx
+ pop es
+ pop ds
+ iret ; Return from interrupt
+
+cprocend
+
+;----------------------------------------------------------------------------
+; int PM_criticalError(int *axVal,int *diVal,int clearFlag)
+;----------------------------------------------------------------------------
+; Returns the current state of the critical error flags, and the values that
+; MSDOS passed in the AX and DI registers to our handler.
+;----------------------------------------------------------------------------
+cprocstart PM_criticalError
+
+ ARG axVal:DPTR, diVal:DPTR, clearFlag:UINT
+
+ enter_c
+ pushf ; Save interrupt status
+ push es
+ifdef flatmodel
+ mov ebx,[_PM_critPtr]
+else
+ les bx,[_PM_critPtr]
+endif
+ cli ; No interrupts thanks!
+ xor _ax,_ax
+ xor _di,_di
+ mov ax,[_ES _bx]
+ mov di,[_ES _bx+2]
+ test [BYTE clearFlag],1
+ jz @@NoClear
+ mov [ULONG _ES _bx],0
+@@NoClear:
+ _les _bx,[axVal]
+ mov [_ES _bx],_ax
+ _les _bx,[diVal]
+ mov [_ES _bx],_di
+ pop es
+ popf ; Restore interrupt status
+ leave_c
+ ret
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_setMouseHandler(int mask, PM_mouseHandler mh)
+;----------------------------------------------------------------------------
+cprocstart _PM_setMouseHandler
+
+ ARG mouseMask:UINT
+
+ enter_c
+ push es
+
+ mov ax,0Ch ; AX := Function 12 - install interrupt sub
+ mov _cx,[mouseMask] ; CX := mouse mask
+ mov _dx,offset _PM_mouseISR
+ push cs
+ pop es ; ES:_DX -> mouse handler
+ int 33h ; Call mouse driver
+
+ pop es
+ leave_c
+ ret
+
+cprocend
+
+ifdef flatmodel
+
+;----------------------------------------------------------------------------
+; void PM_mousePMCB(void)
+;----------------------------------------------------------------------------
+; Mouse realmode callback routine. Upon entry to this routine, we recieve
+; the following from the DPMI server:
+;
+; Entry: DS:_SI -> Real mode stack at time of call
+; ES:_DI -> Real mode register data structure
+; SS:_SP -> Locked protected mode stack to use
+;----------------------------------------------------------------------------
+cprocfar _PM_mousePMCB
+
+ pushad
+ mov eax,[es:_di+1Ch] ; Load register values from real mode
+ mov ebx,[es:_di+10h]
+ mov ecx,[es:_di+18h]
+ mov edx,[es:_di+14h]
+ mov esi,[es:_di+04h]
+ mov edi,[es:_di]
+ call _PM_mouseISR ; Call the mouse handler
+ popad
+
+ mov ax,[ds:_si]
+ mov [es:_di+2Ah],ax ; Plug in return IP address
+ mov ax,[ds:_si+2]
+ mov [es:_di+2Ch],ax ; Plug in return CS value
+ add [WORD es:_di+2Eh],4 ; Remove return address from stack
+ iret ; Go back to real mode!
+
+cprocend
+
+;----------------------------------------------------------------------------
+; void PM_int10PMCB(void)
+;----------------------------------------------------------------------------
+; int10 realmode callback routine. Upon entry to this routine, we recieve
+; the following from the DPMI server:
+;
+; Entry: DS:ESI -> Real mode stack at time of call
+; ES:EDI -> Real mode register data structure
+; SS:ESP -> Locked protected mode stack to use
+;----------------------------------------------------------------------------
+cprocfar _PM_int10PMCB
+
+ pushad
+ push ds
+ push es
+ push fs
+
+ pushfd
+ pop eax
+ mov [es:edi+20h],ax ; Save return flag status
+ mov ax,[ds:esi]
+ mov [es:edi+2Ah],ax ; Plug in return IP address
+ mov ax,[ds:esi+2]
+ mov [es:edi+2Ch],ax ; Plug in return CS value
+ add [WORD es:edi+2Eh],4 ; Remove return address from stack
+
+; Call the install int10 handler in protected mode. This function gets called
+; with DS set to the current data selector, and ES:EDI pointing the the
+; real mode DPMI register structure at the time of the interrupt. The
+; handle must be written in assembler to be able to extract the real mode
+; register values from the structure
+
+ push es
+ pop fs ; FS:EDI -> real mode registers
+ LOAD_DS
+ NEWSTK Int10Stack ; Switch to local stack
+
+ call [_PM_int10Handler]
+
+ RESTSTK Int10Stack ; Restore previous stack
+ pop fs
+ pop es
+ pop ds
+ popad
+ iret ; Go back to real mode!
+
+cprocend
+
+endif
+
+cpublic _PM_pmdosCodeEnd
+
+endcodeseg _pmdos
+
+ END ; End of module
OpenPOWER on IntegriCloud