482 lines
13 KiB
NASM
482 lines
13 KiB
NASM
TITLE "Interrupt Object Support Routines"
|
|
;++
|
|
;
|
|
; Copyright (c) 1989 Microsoft Corporation
|
|
;
|
|
; Module Name:
|
|
;
|
|
; intsup.asm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; This module implements the code necessary to support interrupt objects.
|
|
; It contains the interrupt dispatch code and the code template that gets
|
|
; copied into an interrupt object.
|
|
;
|
|
; Author:
|
|
;
|
|
; Shie-Lin Tzong (shielint) 20-Jan-1990
|
|
;
|
|
; Environment:
|
|
;
|
|
; Kernel mode only.
|
|
;
|
|
; Revision History:
|
|
;
|
|
;--
|
|
.386p
|
|
.xlist
|
|
KERNELONLY equ 1
|
|
include ks386.inc
|
|
include i386\kimacro.inc
|
|
include callconv.inc
|
|
.list
|
|
|
|
EXTRNP KfRaiseIrql,1,,FASTCALL
|
|
EXTRNP KfLowerIrql,1,,FASTCALL
|
|
EXTRNP _KeBugCheck,1
|
|
EXTRNP _KiDeliverApc,0
|
|
EXTRNP HalBeginSystemInterrupt,2,,FASTCALL
|
|
EXTRNP HalEndSystemInterrupt,1,,FASTCALL
|
|
EXTRNP HalEndSystemLevelInterrupt,1,,FASTCALL
|
|
extrn HalpSpecialDismissTable:DWORD
|
|
extrn _KiPCR:DWORD
|
|
if DBG
|
|
extrn _DbgPrint:near
|
|
extrn _MsgISRTimeout:BYTE
|
|
extrn _MsgISROverflow:BYTE
|
|
extrn _KeTickCount:DWORD
|
|
extrn _KiISRTimeout:DWORD
|
|
extrn _KiISROverflow:DWORD
|
|
endif
|
|
|
|
_DATA SEGMENT DWORD PUBLIC 'DATA'
|
|
|
|
if DBG
|
|
COMM KiInterruptCounts:dword:16*2
|
|
endif
|
|
|
|
_DATA ends
|
|
|
|
page ,132
|
|
subttl "Synchronize Execution"
|
|
|
|
_TEXT SEGMENT PARA PUBLIC 'CODE'
|
|
|
|
;++
|
|
;
|
|
; BOOLEAN
|
|
; KeSynchronizeExecution (
|
|
; IN PKINTERRUPT Interrupt,
|
|
; IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
|
|
; IN PVOID SynchronizeContext
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function synchronizes the execution of the specified routine with the
|
|
; execution of the service routine associated with the specified interrupt
|
|
; object.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; Interrupt - Supplies a pointer to a control object of type interrupt.
|
|
;
|
|
; SynchronizeRoutine - Supplies a pointer to a function whose execution
|
|
; is to be synchronized with the execution of the service routine associated
|
|
; with the specified interrupt object.
|
|
;
|
|
; SynchronizeContext - Supplies a pointer to an arbitrary data structure
|
|
; which is to be passed to the function specified by the SynchronizeRoutine
|
|
; parameter.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; The value returned by the SynchronizeRoutine function is returned as the
|
|
; function value.
|
|
;
|
|
;--
|
|
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
|
|
cPublicProc _KeSynchronizeExecution ,3
|
|
|
|
; equates of Local variables
|
|
|
|
KsePreviousIrql equ [ebp - 4] ; previous IRQL
|
|
KseStackSize = 4 * 1
|
|
|
|
; equates for arguments
|
|
|
|
KseInterrupt equ [ebp +8]
|
|
KseSynchronizeRoutine equ [ebp + 12]
|
|
KseSynchronizeContext equ [ebp + 16]
|
|
|
|
push ebp ; save ebp
|
|
mov ebp, esp ; (ebp)-> base of local variable frame
|
|
sub esp, KseStackSize ; allocate local variables space
|
|
push ebx ; save ebx
|
|
|
|
; Acquire the associated spin lock and raise IRQL to the interrupting source.
|
|
|
|
mov ebx, KseInterrupt ; (ebx)->interrupt object
|
|
|
|
mov ecx, InIrql[ebx] ; (ecx) = Synchronize Irql
|
|
fstCall KfRaiseIrql
|
|
mov KsePreviousIrql, al
|
|
|
|
; Call specified routine passing the specified context parameter.
|
|
mov eax,KseSynchronizeContext
|
|
push eax
|
|
call KseSynchronizeRoutine
|
|
mov ebx, eax ; save function returned value
|
|
|
|
; Unlock spin lock, lower IRQL to its previous level, and return the value
|
|
; returned by the specified routine.
|
|
|
|
mov ecx, KsePreviousIrql
|
|
fstCall KfLowerIrql
|
|
|
|
mov eax, ebx ; (eax) = returned value
|
|
pop ebx ; restore ebx
|
|
leave ; will clear stack
|
|
stdRET _KeSynchronizeExecution
|
|
|
|
stdENDP _KeSynchronizeExecution
|
|
|
|
page ,132
|
|
subttl "Interrupt Dispatch"
|
|
;++
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This routine is entered as the result of an interrupt being generated
|
|
; via a vector that is connected to an interrupt object. Its function is
|
|
; to directly call the specified interrupt service routine.
|
|
;
|
|
; This version is used for edge sensitive interrupts.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; edi - Supplies a pointer to the interrupt object.
|
|
; esp - Supplies a pointer to the top of trap frame
|
|
; ebp - Supplies a pointer to the top of trap frame
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
align 16
|
|
cPublicProc _KiInterruptDispatch ,0
|
|
.FPO (2, 0, 0, 0, 0, 1)
|
|
|
|
;
|
|
; update statistic
|
|
;
|
|
inc dword ptr PCR[PcPrcbData+PbInterruptCount]
|
|
|
|
;
|
|
; Save previous IRQL and set new priority level
|
|
;
|
|
; Instead of invoking HalBeginSystemInterrupt, we call indirect through the
|
|
; dismiss table ourselves.
|
|
;
|
|
|
|
mov ecx, [edi].InBusInterruptLevel
|
|
mov edx, [edi].InIrql
|
|
push 0 ; make room for OldIrql
|
|
call HalpSpecialDismissTable[ecx*4]
|
|
|
|
;
|
|
; Call the service routine.
|
|
;
|
|
|
|
if DBG
|
|
mov ebx, [edi].InBusInterruptLevel ; this vector
|
|
mov eax, _KeTickCount ; current time
|
|
and eax, NOT 31 ; mask to closest 1/2 second
|
|
shl ebx, 3 ; eax = eax * 8
|
|
cmp eax, [KiInterruptCounts+ebx] ; in same 1/2 range?
|
|
jne kid_overflowreset
|
|
|
|
mov eax, _KiISROverflow
|
|
inc [KiInterruptCounts+ebx+4]
|
|
cmp [KiInterruptCounts+ebx+4], eax
|
|
jnc kid_interruptoverflow
|
|
kid_dbg2:
|
|
mov ebx, _KeTickCount
|
|
endif
|
|
mov eax, InServiceContext[edi] ; set parameter value
|
|
push eax
|
|
push edi ; pointer to interrupt object
|
|
call InServiceRoutine[edi] ; call specified routine
|
|
|
|
if DBG
|
|
add ebx, _KiISRTimeout ; adjust for ISR timeout
|
|
cmp _KeTickCount, ebx ; Did ISR timeout?
|
|
jnc kid200
|
|
kid31:
|
|
endif
|
|
|
|
;
|
|
; Do interrupt exit processing
|
|
;
|
|
|
|
INTERRUPT_EXIT ; will do an iret
|
|
|
|
;
|
|
; ISR took a long time to complete, abort to debugger
|
|
;
|
|
|
|
if DBG
|
|
kid200: push InServiceRoutine[edi] ; timed out
|
|
push offset FLAT:_MsgISRTimeout
|
|
call _DbgPrint
|
|
add esp,8
|
|
int 3
|
|
jmp kid31 ; continue
|
|
|
|
kid_interruptoverflow:
|
|
push [KiInterruptCounts+ebx+4]
|
|
push InServiceRoutine[edi]
|
|
push offset FLAT:_MsgISROverflow
|
|
call _DbgPrint
|
|
add esp,12
|
|
int 3
|
|
|
|
mov eax, _KeTickCount ; current time
|
|
and eax, NOT 31 ; mask to closest 1/2 second
|
|
|
|
kid_overflowreset:
|
|
mov [KiInterruptCounts+ebx], eax ; initialize time
|
|
mov [KiInterruptCounts+ebx+4], 0 ; reset count
|
|
jmp kid_dbg2
|
|
endif
|
|
|
|
|
|
stdENDP _KiInterruptDispatch
|
|
|
|
page ,132
|
|
subttl "Level Interrupt Dispatch"
|
|
;++
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This routine is entered as the result of an interrupt being generated
|
|
; via a vector that is connected to an interrupt object. Its function is
|
|
; to directly call the specified interrupt service routine.
|
|
;
|
|
; This version is used for level sensitive interrupts.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; edi - Supplies a pointer to the interrupt object.
|
|
; esp - Supplies a pointer to the top of trap frame
|
|
; ebp - Supplies a pointer to the top of trap frame
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
align 16
|
|
cPublicProc _KiLevelInterruptDispatch ,0
|
|
.FPO (2, 0, 0, 0, 0, 1)
|
|
|
|
;
|
|
; update statistic
|
|
;
|
|
inc dword ptr PCR[PcPrcbData+PbInterruptCount]
|
|
|
|
;
|
|
; Save previous IRQL and set new priority level
|
|
;
|
|
; Instead of invoking HalBeginSystemInterrupt, we call indirect through the
|
|
; dismiss table ourselves.
|
|
;
|
|
|
|
mov ecx, [edi].InBusInterruptLevel
|
|
mov edx, [edi].InIrql
|
|
push 0 ; make room for OldIrql
|
|
call HalpSpecialDismissTable[ecx*4]
|
|
|
|
;
|
|
; Call the service routine.
|
|
;
|
|
|
|
if DBG
|
|
mov ebx, [edi].InBusInterruptLevel ; this vector
|
|
mov eax, _KeTickCount ; current time
|
|
and eax, NOT 31 ; mask to closest 1/2 second
|
|
shl ebx, 3 ; eax = eax * 8
|
|
cmp eax, [KiInterruptCounts+ebx] ; in same 1/2 range?
|
|
jne klid_overflowreset
|
|
|
|
mov eax, _KiISROverflow
|
|
inc [KiInterruptCounts+ebx+4]
|
|
cmp [KiInterruptCounts+ebx+4], eax
|
|
jnc klid_interruptoverflow
|
|
klid_dbg2:
|
|
mov ebx, _KeTickCount
|
|
endif
|
|
mov eax, InServiceContext[edi] ; set parameter value
|
|
push eax
|
|
push edi ; pointer to interrupt object
|
|
call InServiceRoutine[edi] ; call specified routine
|
|
|
|
if DBG
|
|
add ebx, _KiISRTimeout ; adjust for ISR timeout
|
|
cmp _KeTickCount, ebx ; Did ISR timeout?
|
|
jnc klid200
|
|
klid31:
|
|
endif
|
|
|
|
;
|
|
; Do interrupt exit processing
|
|
;
|
|
|
|
mov eax, [edi].InBusInterruptLevel
|
|
LEVEL_INTERRUPT_EXIT
|
|
|
|
;
|
|
; ISR took a long time to complete, abort to debugger
|
|
;
|
|
|
|
if DBG
|
|
klid200: push InServiceRoutine[edi] ; timed out
|
|
push offset FLAT:_MsgISRTimeout
|
|
call _DbgPrint
|
|
add esp,8
|
|
int 3
|
|
jmp klid31 ; continue
|
|
|
|
klid_interruptoverflow:
|
|
push [KiInterruptCounts+ebx+4]
|
|
push InServiceRoutine[edi]
|
|
push offset FLAT:_MsgISROverflow
|
|
call _DbgPrint
|
|
add esp,12
|
|
int 3
|
|
|
|
mov eax, _KeTickCount ; current time
|
|
and eax, NOT 31 ; mask to closest 1/2 second
|
|
|
|
klid_overflowreset:
|
|
mov [KiInterruptCounts+ebx], eax ; initialize time
|
|
mov [KiInterruptCounts+ebx+4], 0 ; reset count
|
|
jmp klid_dbg2
|
|
endif
|
|
|
|
stdENDP _KiLevelInterruptDispatch
|
|
|
|
page ,132
|
|
subttl "Interrupt Template"
|
|
;++
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This routine is a template that is copied into each interrupt object. Its
|
|
; function is to save machine state and pass the address of the respective
|
|
; interrupt object and transfer control to the appropriate interrupt
|
|
; dispatcher.
|
|
;
|
|
; Control comes here through i386 interrupt gate and, upon entry, the
|
|
; interrupt is disabled.
|
|
;
|
|
; Note: If the length of this template changed, the corresponding constant
|
|
; defined in Ki.h needs to be updated accordingly.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None
|
|
;
|
|
; Return Value:
|
|
;
|
|
; edi - addr of interrupt object
|
|
; esp - top of trap frame
|
|
; interrupts are disabled
|
|
;
|
|
;--
|
|
|
|
_KiShutUpAssembler proc
|
|
|
|
public _KiInterruptTemplate
|
|
_KiInterruptTemplate label byte
|
|
|
|
; Save machine state on trap frame
|
|
|
|
ENTER_INTERRUPT
|
|
|
|
;
|
|
; the following instruction gets the addr of associated interrupt object.
|
|
; the value ? will be replaced by REAL interrupt object address at
|
|
; interrupt object initialization time.
|
|
; mov edi, addr of interrupt object
|
|
;
|
|
; Template modifications made to support BBT, include replacing bogus
|
|
; insructions (created by db and dd) with real instructions.
|
|
; This stuff gets overwritten anyway. BBT just needs to see real instructions.
|
|
|
|
public _KiInterruptTemplate2ndDispatch
|
|
_KiInterruptTemplate2ndDispatch equ this dword
|
|
mov edi,0
|
|
|
|
public _KiInterruptTemplateObject
|
|
_KiInterruptTemplateObject equ this dword
|
|
|
|
; the following instruction transfers control to the appropriate dispatcher
|
|
; code. The value ? will be replaced by real InterruptObj.DispatchAddr
|
|
; at interrupt initialization time. The dispatcher routine will be any one
|
|
; of _KiInterruptDispatch or _KiChainDispatch.
|
|
; jmp [IntObj.DispatchAddr]
|
|
|
|
db 0E9h, 0, 0, 0, 0
|
|
|
|
public _KiInterruptTemplateDispatch
|
|
_KiInterruptTemplateDispatch equ this dword
|
|
|
|
; end of _KiInterruptTemplate
|
|
|
|
; The template must fit in the KINTERRUPT.DispatchCode[DISPATCH_LENGTH] field.
|
|
.errnz (($ - _KiInterruptTemplate) GT DISPATCH_LENGTH)
|
|
|
|
_KiShutUpAssembler endp
|
|
|
|
page ,132
|
|
subttl "Unexpected Interrupt"
|
|
;++
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This routine is entered as the result of an interrupt being generated
|
|
; via a vector that is not connected to an interrupt object.
|
|
;
|
|
; For any unconnected vector, its associated 8259 irq is masked out at
|
|
; Initialization time. So, this routine should NEVER be called.
|
|
; If somehow, this routine gets control we simple raise a BugCheck and
|
|
; stop the system.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; None
|
|
; Interrupt is disabled
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
public _KiUnexpectedInterrupt
|
|
_KiUnexpectedInterrupt proc
|
|
cPublicFpo 0,0
|
|
|
|
; stop the system
|
|
stdCall _KeBugCheck, <TRAP_CAUSE_UNKNOWN>
|
|
nop
|
|
|
|
_KiUnexpectedInterrupt endp
|
|
|
|
_TEXT ends
|
|
end
|