775 lines
22 KiB
ArmAsm
775 lines
22 KiB
ArmAsm
|
// TITLE("Interrupt Object Support Routines")
|
|||
|
//++
|
|||
|
//
|
|||
|
// Module Name:
|
|||
|
//
|
|||
|
// intsup.s
|
|||
|
//
|
|||
|
// 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:
|
|||
|
//
|
|||
|
// Bernard Lint 20-Nov-1995
|
|||
|
//
|
|||
|
// Environment:
|
|||
|
//
|
|||
|
// Kernel mode only.
|
|||
|
//
|
|||
|
// Revision History:
|
|||
|
//
|
|||
|
// Based on MIPS version (David N. Cutler (davec) 2-Apr-1990)
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
#include "ksia64.h"
|
|||
|
//
|
|||
|
SBTTL("Synchronize Execution")
|
|||
|
//++
|
|||
|
//
|
|||
|
// 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 (a0) - Supplies a pointer to a control object of type interrupt.
|
|||
|
//
|
|||
|
// SynchronizeRoutine (a1) - 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 (a2) - 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.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
NESTED_ENTRY(KeSynchronizeExecution)
|
|||
|
NESTED_SETUP(3,4,1,0)
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
// Register aliases for entire procedure
|
|||
|
//
|
|||
|
|
|||
|
rOldIrql = loc2 // saved IRQL value
|
|||
|
rpSpinLock= loc3 // address of spin lock
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to the synchronization level and acquire the associated
|
|||
|
// spin lock.
|
|||
|
//
|
|||
|
|
|||
|
ARGPTR (a0)
|
|||
|
ARGPTR (a1)
|
|||
|
add t2 = InSynchronizeIrql, a0 // -> sync IRQL
|
|||
|
;;
|
|||
|
ld1 t3 = [t2], InActualLock-InSynchronizeIrql
|
|||
|
;;
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
LDPTR (rpSpinLock, t2) // get address of spin lock
|
|||
|
|
|||
|
#endif // !defined(NT_UP)
|
|||
|
|
|||
|
|
|||
|
GET_IRQL(rOldIrql) // save old IRQL
|
|||
|
SET_IRQL(t3) // raise IRQL to synchronization IRQL
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
ACQUIRE_SPINLOCK(rpSpinLock, rpSpinLock, Kse10)
|
|||
|
|
|||
|
#endif // !defined(NT_UP)
|
|||
|
|
|||
|
//
|
|||
|
// Call specified routine passing the specified context parameter.
|
|||
|
//
|
|||
|
|
|||
|
ld8 t1 = [a1], PlGlobalPointer-PlEntryPoint
|
|||
|
;;
|
|||
|
ld8 gp = [a1]
|
|||
|
mov bt0 = t1 // setup br
|
|||
|
mov out0 = a2 // get synchronize context
|
|||
|
br.call.sptk.many brp = bt0 // call routine
|
|||
|
|
|||
|
//
|
|||
|
// Release spin lock, lower IRQL to its previous level, and return the value
|
|||
|
// returned by the specified routine.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
RELEASE_SPINLOCK(rpSpinLock)
|
|||
|
|
|||
|
#endif // !defined(NT_UP)
|
|||
|
|
|||
|
SET_IRQL(rOldIrql) // lower IRQL to previous level
|
|||
|
NESTED_RETURN
|
|||
|
NESTED_EXIT(KeSynchronizeExecution)
|
|||
|
//
|
|||
|
SBTTL("Chained Dispatch")
|
|||
|
//++
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine is entered as the result of an interrupt being generated
|
|||
|
// via a vector that is connected to more than one interrupt object. Its
|
|||
|
// function is to walk the list of connected interrupt objects and call
|
|||
|
// each interrupt service routine. If the mode of the interrupt is latched,
|
|||
|
// then a complete traversal of the chain must be performed. If any of the
|
|||
|
// routines require saving the volatile floating point machine state, then
|
|||
|
// it is only saved once.
|
|||
|
//
|
|||
|
// N.B. On entry to this routine only the volatile integer registers have
|
|||
|
// been saved. Also the volatile lower floating point registers saved.
|
|||
|
//
|
|||
|
// N.B. gp will be destroyed by the interrupt service routine; if this code
|
|||
|
// uses the gp of this module after the call, then it must save and
|
|||
|
// restore gp.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// a0 - Supplies a function pointer to the ISR (in the interrupt object
|
|||
|
// dispatch code).
|
|||
|
//
|
|||
|
// a1 - Supplies a pointer to a trap frame.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
NESTED_ENTRY(KiChainedDispatch)
|
|||
|
NESTED_SETUP(2,7,2,0)
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
// Register aliases
|
|||
|
//
|
|||
|
|
|||
|
rpSpinLock = loc2 // pointer to spinlock
|
|||
|
rMode = loc3 // interrupt mode (level sensitive)
|
|||
|
rpEntry = loc4 // current list entry
|
|||
|
rIrql = loc5 // source interrupt IRQL
|
|||
|
rSirql = loc6 // new interrupt IRQL
|
|||
|
rpI1 = t0 // temp pointer
|
|||
|
rpI2 = t1 // temp pointer
|
|||
|
rpFptr = t2 // pointer to ISR fptr
|
|||
|
rpCtxt = t3 // pointer to service context
|
|||
|
rFptr = t4 // ISR fptr
|
|||
|
|
|||
|
pLoop1 = pt1 // do another loop
|
|||
|
pLoop2 = pt2 // do another loop
|
|||
|
pNEqual = ps0 // true if source IRQL != sync IRQL
|
|||
|
|
|||
|
//
|
|||
|
// Initialize loop variables.
|
|||
|
//
|
|||
|
|
|||
|
add out0 = -InDispatchCode, a0 // out0 -> interrupt object
|
|||
|
;;
|
|||
|
add rpEntry = InInterruptListEntry, out0 // set address of listhead
|
|||
|
add rpI1 = InMode, out0 // -> mode of interrupt
|
|||
|
add rpI2 = InIrql, out0 // -> interrupt source IRQL
|
|||
|
;;
|
|||
|
ld1 rMode = [rpI1] // get mode of interrupt
|
|||
|
ld1 rIrql = [rpI2] // get interrupt source IRQL
|
|||
|
|
|||
|
//
|
|||
|
// Walk the list of connected interrupt objects and call the respective
|
|||
|
// interrupt service routines.
|
|||
|
//
|
|||
|
// Raise IRQL to synchronization level if synchronization level is not
|
|||
|
// equal to the interrupt source level.
|
|||
|
//
|
|||
|
|
|||
|
Kcd_Loop:
|
|||
|
add rpI1 = InSynchronizeIrql, out0
|
|||
|
;;
|
|||
|
ld1 rSirql = [rpI1], InActualLock-InSynchronizeIrql
|
|||
|
;;
|
|||
|
|
|||
|
cmp.ne pNEqual = rIrql, rSirql // if ne, IRQL levels are
|
|||
|
// not the same
|
|||
|
;;
|
|||
|
PSET_IRQL(pNEqual, rSirql) // raise to synchronization IRQL
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// Acquire the service routine spin lock and call the service routine.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
LDPTR (rpSpinLock, rpI1) // get address of spin lock
|
|||
|
|
|||
|
ACQUIRE_SPINLOCK(rpSpinLock, rpSpinLock, Kcd_Lock)
|
|||
|
|
|||
|
#endif // !defined(NT_UP)
|
|||
|
|
|||
|
add rpFptr = InServiceRoutine, out0 // pointer to fptr
|
|||
|
add rpCtxt = InServiceContext, out0 // pointer to service context
|
|||
|
;;
|
|||
|
LDPTR (rFptr, rpFptr) // get fptr
|
|||
|
LDPTR (out1, rpCtxt) // get service context
|
|||
|
;;
|
|||
|
ld8 t5 = [rFptr], PlGlobalPointer-PlEntryPoint
|
|||
|
;;
|
|||
|
ld8 gp = [rFptr]
|
|||
|
mov bt0 = t5 // set br address
|
|||
|
br.call.sptk brp = bt0 // call ISR
|
|||
|
|
|||
|
//
|
|||
|
// Release the service routine spin lock.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
RELEASE_SPINLOCK(rpSpinLock)
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Lower IRQL to the interrupt source level if synchronization level is not
|
|||
|
// the same as the interrupt source level.
|
|||
|
//
|
|||
|
|
|||
|
PSET_IRQL(pNEqual,rIrql)
|
|||
|
|
|||
|
//
|
|||
|
// Get next list entry and check for end of loop.
|
|||
|
//
|
|||
|
|
|||
|
add rpI1 = LsFlink, rpEntry // -> next entry
|
|||
|
;;
|
|||
|
LDPTR (rpEntry, rpI1) // -> next interrupt object
|
|||
|
;;
|
|||
|
|
|||
|
//
|
|||
|
// Loop if (1) interrrupt not handled and not end of list or
|
|||
|
// if (2) interrupt handled, and not level sensistive, and not end of list
|
|||
|
//
|
|||
|
|
|||
|
cmp4.eq pLoop1 = zero, zero // initialize pLoop1
|
|||
|
cmp4.eq pLoop2 = zero, zero // initialize pLoop2
|
|||
|
add out0 = -InInterruptListEntry, rpEntry // -> next interrupt object
|
|||
|
;;
|
|||
|
|
|||
|
cmp4.eq.and pLoop1 = zero, v0 // if eq, interrupt not handled
|
|||
|
cmp.ne.and pLoop1, pLoop2 = zero, rpEntry // if ne, not end of list
|
|||
|
(pLoop1) br.dptk Kcd_Loop // loop to handle next enrty
|
|||
|
|
|||
|
cmp4.ne.and pLoop2 = zero, v0 // if ne, interrupt handled
|
|||
|
cmp4.ne.and pLoop2 = zero, rMode // if ne, not level sensitive
|
|||
|
(pLoop2) br.dptk Kcd_Loop // loop to handle next enrty
|
|||
|
|
|||
|
//
|
|||
|
// Either the interrupt is level sensitive and has been handled or the end of
|
|||
|
// the interrupt object chain has been reached.
|
|||
|
//
|
|||
|
|
|||
|
NESTED_RETURN
|
|||
|
NESTED_EXIT(KiChainedDispatch)
|
|||
|
|
|||
|
SBTTL("Interrupt Dispatch - Raise IRQL")
|
|||
|
//++
|
|||
|
//
|
|||
|
// 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.
|
|||
|
//
|
|||
|
// N.B. On entry to this routine only the volatile integer registers have
|
|||
|
// been saved. Also volatile lower floating point registers saved.
|
|||
|
//
|
|||
|
// N.B. This routine raises the interrupt level to the synchronization
|
|||
|
// level specified in the interrupt object.
|
|||
|
//
|
|||
|
// N.B. gp will be destroyed by the interrupt service routine; if this code
|
|||
|
// uses the gp of this module after the call, then it must save and
|
|||
|
// restore gp.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// a0 - Supplies a function pointer to the ISR (in the interrupt object
|
|||
|
// dispatch code).
|
|||
|
//
|
|||
|
// a1 - Supplies a pointer to a trap frame.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
NESTED_ENTRY(KiInterruptDispatchRaise)
|
|||
|
NESTED_SETUP(2,4,2,0)
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
// Register aliases
|
|||
|
//
|
|||
|
|
|||
|
rpSpinLock = loc2
|
|||
|
rSirql = loc3 // sync IRQL
|
|||
|
rpI1 = t1 // temp pointer
|
|||
|
rpFptr = t2 // pointer to ISR function pointer
|
|||
|
rpCtxt = t3 // pointer to service context
|
|||
|
rFptr = t4 // ISR function pointer (plabel pointer)
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to synchronization level.
|
|||
|
//
|
|||
|
|
|||
|
add out0 = -InDispatchCode, a0 // out0 -> interrupt object
|
|||
|
add rpI1 = InSynchronizeIrql-InDispatchCode, a0
|
|||
|
;;
|
|||
|
|
|||
|
ld1 rSirql = [rpI1], InActualLock-InSynchronizeIrql
|
|||
|
;;
|
|||
|
SET_IRQL(rSirql) // raise to synchronization IRQL
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// Acquire the service routine spin lock and call the service routine.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
LDPTR (rpSpinLock, rpI1) // get address of spin lock
|
|||
|
;;
|
|||
|
ACQUIRE_SPINLOCK(rpSpinLock, rpSpinLock, Kidr_Lock)
|
|||
|
|
|||
|
#endif // !defined(NT_UP)
|
|||
|
|
|||
|
add rpFptr = InServiceRoutine, out0 // pointer to fptr
|
|||
|
add rpCtxt = InServiceContext, out0 // pointer to service context
|
|||
|
;;
|
|||
|
LDPTR (rFptr, rpFptr) // get fptr
|
|||
|
LDPTR (out1, rpCtxt) // get service context
|
|||
|
;;
|
|||
|
ld8 t5 = [rFptr], PlGlobalPointer-PlEntryPoint
|
|||
|
;;
|
|||
|
ld8 gp = [rFptr]
|
|||
|
mov bt0 = t5 // set br address
|
|||
|
br.call.sptk brp = bt0 // call ISR
|
|||
|
|
|||
|
//
|
|||
|
// Release the service routine spin lock.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
RELEASE_SPINLOCK(rpSpinLock)
|
|||
|
|
|||
|
#endif // !defined(NT_UP)
|
|||
|
|
|||
|
//
|
|||
|
// IRQL lowered to the previous level in the external handler.
|
|||
|
//
|
|||
|
|
|||
|
NESTED_RETURN
|
|||
|
NESTED_EXIT(KiInterruptDispatchRaise)
|
|||
|
//
|
|||
|
SBTTL("Interrupt Dispatch - Same IRQL")
|
|||
|
//++
|
|||
|
//
|
|||
|
// 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.
|
|||
|
//
|
|||
|
// N.B. On entry to this routine only the volatile integer registers have
|
|||
|
// been saved. Also the volatile lower float point registers.
|
|||
|
//
|
|||
|
// N.B. gp will be destroyed by the interrupt service routine; if this code
|
|||
|
// uses the gp of this module after the call, then it must save and
|
|||
|
// restore gp.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// a0 - Supplies a function pointer to the ISR (in the interrupt object
|
|||
|
// dispatch code).
|
|||
|
//
|
|||
|
// a1 - Supplies a pointer to a trap frame..
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
#if defined(NT_UP)
|
|||
|
|
|||
|
LEAF_ENTRY(KiInterruptDispatchSame)
|
|||
|
//
|
|||
|
// Register aliases
|
|||
|
//
|
|||
|
|
|||
|
rpFptr = t2 // pointer to ISR function pointer
|
|||
|
rFptr = t4 // ISR function pointer (plabel pointer)
|
|||
|
|
|||
|
add a0 = -InDispatchCode, a0 // a0 points to interrupt object
|
|||
|
;;
|
|||
|
add rpFptr = InServiceRoutine, a0 // -> service routine fptr
|
|||
|
add t1 = InServiceContext, a0 // -> service context
|
|||
|
;;
|
|||
|
LDPTR (rFptr, rpFptr) // service routine fptr
|
|||
|
LDPTR (a1, t1) // service context
|
|||
|
;;
|
|||
|
ld8 t5 = [rFptr], PlGlobalPointer-PlEntryPoint
|
|||
|
;;
|
|||
|
ld8 gp = [rFptr]
|
|||
|
mov bt0 = t5
|
|||
|
br.sptk bt0 // jump to service routine
|
|||
|
|
|||
|
//
|
|||
|
// N.B.: Return to trap handler from ISR.
|
|||
|
//
|
|||
|
|
|||
|
LEAF_EXIT(KiInterruptDispatchSame)
|
|||
|
#else
|
|||
|
|
|||
|
NESTED_ENTRY(KiInterruptDispatchSame)
|
|||
|
NESTED_SETUP(2,3,2,0)
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
// Register aliases
|
|||
|
//
|
|||
|
|
|||
|
rpSpinLock = loc2
|
|||
|
rpFptr = t2 // -> ISR function pointer
|
|||
|
rpCtxt = t3 // -> service context
|
|||
|
rFptr = t4 // ISR function pointer (plabel pointer)
|
|||
|
//
|
|||
|
//
|
|||
|
// Acquire the service routine spin lock and call the service routine.
|
|||
|
//
|
|||
|
|
|||
|
add out0 = -InDispatchCode, a0 // -> interrupt object
|
|||
|
;;
|
|||
|
add t1 = InActualLock, out0 // pointer to address of lock
|
|||
|
add rpCtxt = InServiceContext,out0
|
|||
|
;;
|
|||
|
|
|||
|
LDPTR (rpSpinLock, t1) // get address of spin lock
|
|||
|
add rpFptr = InServiceRoutine, out0 // pointer to fptr
|
|||
|
;;
|
|||
|
ACQUIRE_SPINLOCK(rpSpinLock, rpSpinLock, Kids_Lock)
|
|||
|
|
|||
|
LDPTR (rFptr, rpFptr) // get fptr
|
|||
|
LDPTR (out1, rpCtxt) // get service context
|
|||
|
;;
|
|||
|
ld8 t5 = [rFptr], PlGlobalPointer-PlEntryPoint
|
|||
|
;;
|
|||
|
ld8 gp = [rFptr]
|
|||
|
mov bt0 = t5 // set br address
|
|||
|
br.call.sptk brp = bt0 // call ISR
|
|||
|
|
|||
|
//
|
|||
|
// Release the service routine spin lock.
|
|||
|
//
|
|||
|
|
|||
|
RELEASE_SPINLOCK(rpSpinLock)
|
|||
|
|
|||
|
NESTED_RETURN
|
|||
|
|
|||
|
NESTED_EXIT(KiInterruptDispatchSame)
|
|||
|
#endif // !defined(NT_UP)
|
|||
|
|
|||
|
SBTTL("Disable Interrupts")
|
|||
|
//++
|
|||
|
//
|
|||
|
// BOOLEAN
|
|||
|
// KiDisableInterrupts (
|
|||
|
// VOID
|
|||
|
// )
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This function disables interrupts and returns whether interrupts
|
|||
|
// were previously enabled.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// A boolean value that determines whether interrupts were previously
|
|||
|
// enabled (TRUE) or disabled(FALSE).
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiDisableInterrupts)
|
|||
|
|
|||
|
DISABLE_INTERRUPTS(t0) // t0 = previous state
|
|||
|
;;
|
|||
|
tbit.nz pt0, pt1 = t0, PSR_I // pt0 = 1, if enabled; pt1 = 1 if disabled
|
|||
|
;;
|
|||
|
|
|||
|
(pt0) mov v0 = TRUE // set return value -- TRUE if enabled
|
|||
|
(pt1) mov v0 = FALSE // FALSE if disabled
|
|||
|
|
|||
|
LEAF_RETURN
|
|||
|
LEAF_EXIT(KiDisableInterrupts)
|
|||
|
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// KiRestoreInterrupts (
|
|||
|
// IN BOOLEAN Enable
|
|||
|
// )
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This function restores the interrupt enable that was returned by
|
|||
|
// the disable interrupts function.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// Enable (a0) - Supplies the interrupt enable value.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiRestoreInterrupts)
|
|||
|
|
|||
|
dep.z t0 = a0, PSR_I, 1 // enable or disable based on input arg
|
|||
|
;;
|
|||
|
RESTORE_INTERRUPTS(t0)
|
|||
|
|
|||
|
LEAF_RETURN
|
|||
|
LEAF_EXIT(KiRestoreInterrupts)
|
|||
|
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// KiPassiveRelease (
|
|||
|
// VOID
|
|||
|
// )
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This function is called when an interrupt has been passively released.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiPassiveRelease)
|
|||
|
|
|||
|
LEAF_RETURN
|
|||
|
LEAF_EXIT(KiPassiveRelease)
|
|||
|
|
|||
|
|
|||
|
SBTTL("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. Its function
|
|||
|
// is to report the error and dismiss the interrupt.
|
|||
|
//
|
|||
|
// N.B. On entry to this routine only the volatile integer registers have
|
|||
|
// been saved. Also the volatile lower float point registers.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// a0 - Supplies a function pointer to the ISR (in the interrupt object
|
|||
|
// dispatch code).
|
|||
|
//
|
|||
|
// a1 - Supplies a pointer to a trap frame.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiUnexpectedInterrupt)
|
|||
|
|
|||
|
LEAF_RETURN
|
|||
|
LEAF_EXIT(KiUnexpectedInterrupt)
|
|||
|
|
|||
|
|
|||
|
LEAF_ENTRY(KiFloatingDispatch)
|
|||
|
|
|||
|
LEAF_RETURN
|
|||
|
LEAF_EXIT(KiFloatingDispatch)
|
|||
|
|
|||
|
#ifdef notyet
|
|||
|
//
|
|||
|
// Not needed since we always save low floating point regs in TF
|
|||
|
//
|
|||
|
|
|||
|
SBTTL("Floating 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 save the volatile floating machine state and then call the specified
|
|||
|
// interrupt service routine.
|
|||
|
//
|
|||
|
// N.B. On entry to this routine only the volatile integer registers have
|
|||
|
// been saved.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// a0 - Supplies a pointer to the interrupt object.
|
|||
|
//
|
|||
|
// s8 - Supplies a pointer to a trap frame.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
.struct 0
|
|||
|
FlArg: .space 4 * 4 // argument register save area
|
|||
|
FlS0: .space 4 // saved integer registers s0 - s1
|
|||
|
FlS1: .space 4 //
|
|||
|
FlIrql: .space 4 // saved IRQL value
|
|||
|
FlRa: .space 4 // saved return address
|
|||
|
FlFrameLength: // length of stack frame
|
|||
|
|
|||
|
NESTED_ENTRY(KiFloatingDispatch, FlFrameLength, zero)
|
|||
|
|
|||
|
subu sp,sp,FlFrameLength // allocate stack frame
|
|||
|
sw ra,FlRa(sp) // save return address
|
|||
|
sw s0,FlS0(sp) // save integer registers s0 - s1
|
|||
|
|
|||
|
#if defined(R4000) && !defined(NT_UP)
|
|||
|
|
|||
|
sw s1,FlS1(sp) //
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
// Save volatile floating registers f0 - f19 in trap frame.
|
|||
|
//
|
|||
|
|
|||
|
SAVE_VOLATILE_FLOAT_STATE // save volatile floating state
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to synchronization level if synchronization level is not
|
|||
|
// equal to the interrupt source level.
|
|||
|
//
|
|||
|
|
|||
|
move s0,a0 // save address of interrupt object
|
|||
|
lbu a0,InSynchronizeIrql(s0) // get synchronization IRQL
|
|||
|
lbu t0,InIrql(s0) // get interrupt source IRQL
|
|||
|
beq a0,t0,10f // if eq, IRQL levels are the same
|
|||
|
addu a1,sp,FlIrql // compute address to save IRQL
|
|||
|
jal KeRaiseIrql // raise to synchronization IRQL
|
|||
|
10: move a0,s0 // restore address of interrupt object
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// Acquire the service routine spin lock and call the service routine.
|
|||
|
//
|
|||
|
|
|||
|
#if defined(R4000) && !defined(NT_UP)
|
|||
|
|
|||
|
lw s1,InActualLock(a0) // get address of spin lock
|
|||
|
20: ll t1,0(s1) // get current lock value
|
|||
|
move t2,s1 // set lock ownership value
|
|||
|
bne zero,t1,20b // if ne, spin lock owned
|
|||
|
sc t2,0(s1) // set spin lock owned
|
|||
|
beq zero,t2,20b // if eq, store conditional failed
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
lw t0,InServiceRoutine(a0) // get address of service routine
|
|||
|
lw a1,InServiceContext(a0) // get service context
|
|||
|
jal t0 // call service routine
|
|||
|
|
|||
|
//
|
|||
|
// Release the service routine spin lock.
|
|||
|
//
|
|||
|
|
|||
|
#if defined(R4000) && !defined(NT_UP)
|
|||
|
|
|||
|
sw zero,0(s1) // set spin lock not owned
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Lower IRQL to the interrupt source level if synchronization level is not
|
|||
|
// the same as the interrupt source level.
|
|||
|
//
|
|||
|
|
|||
|
lbu a0,InIrql(s0) // get interrupt source IRQL
|
|||
|
lbu t0,InSynchronizeIrql(s0) // get synchronization IRQL
|
|||
|
beq a0,t0,30f // if eq, IRQL levels are the same
|
|||
|
jal KeLowerIrql // lower to interrupt source IRQL
|
|||
|
|
|||
|
//
|
|||
|
// Restore volatile floating registers f0 - f19 from trap frame.
|
|||
|
//
|
|||
|
|
|||
|
30: RESTORE_VOLATILE_FLOAT_STATE // restore volatile floating state
|
|||
|
|
|||
|
//
|
|||
|
// Restore integer registers s0 - s1, retrieve return address, deallocate
|
|||
|
// stack frame, and return.
|
|||
|
//
|
|||
|
|
|||
|
lw s0,FlS0(sp) // restore integer registers s0 - s1
|
|||
|
|
|||
|
#if defined(R4000) && !defined(NT_UP)
|
|||
|
|
|||
|
lw s1,FlS1(sp) //
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
lw ra,FlRa(sp) // restore return address
|
|||
|
addu sp,sp,FlFrameLength // deallocate stack frame
|
|||
|
j ra // return
|
|||
|
|
|||
|
.end KiFloatingDispatch
|
|||
|
#endif // notyet
|