xbox-kernel/private/ntos/ke/i386/intsup.asm
2020-09-30 17:17:25 +02:00

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