⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 _pmdos.asm

📁 AT91RM9200-U-Boot at91rm9200u-boot移植源代码
💻 ASM
📖 第 1 页 / 共 3 页
字号:
        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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -