📄 _pmdos.asm
字号:
pushf ; Save state of interrupt flag pushf ; Push flags on stack to simulate interruptifdef 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 retendifcprocend; 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%endmacroelsemacro DELAY jmp short $+2 jmp short $+2 jmp short $+2endmmacro IODELAYN N rept N DELAY endmendmendif;----------------------------------------------------------------------------; 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 interruptcprocendifdef 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 forptr_IRQStack DUINT 0 ; Place to store old stack offsetseg_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 handlercprocendcpublic _PM_irqISRTemplateEndendif;----------------------------------------------------------------------------; 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 eaxelse pushfifdef USE_NASM call far dword [_PM_prevKey]else call [_PM_prevKey]endifendif jmp @@Exitcprocend;----------------------------------------------------------------------------; 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_chainPrevKeyifdef 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 retelse; 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 interruptifdef USE_NASM call far dword [_PM_prevKey]else call [_PM_prevKey]endif SWAPSTK KyStack ; Swap back to C stack again retendifcprocend;----------------------------------------------------------------------------; 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -