933 lines
29 KiB
ArmAsm
933 lines
29 KiB
ArmAsm
|
// TITLE("Interrupt Object Support Routines")
|
|||
|
//++
|
|||
|
//
|
|||
|
// Copyright (c) 1990 Microsoft Corporation
|
|||
|
// Copyright (c) 1992 Digital Equipment Corporation
|
|||
|
//
|
|||
|
// 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:
|
|||
|
//
|
|||
|
// David N. Cutler (davec) 2-Apr-1990
|
|||
|
// Joe Notarangelo 07-Apr-1992 (based on xxintsup.s by Dave Cutler)
|
|||
|
//
|
|||
|
// Environment:
|
|||
|
//
|
|||
|
// Kernel mode only.
|
|||
|
//
|
|||
|
// Revision History:
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
#include "ksalpha.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.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
|
|||
|
.struct 0
|
|||
|
SyS0: .space 8 // saved integer register s0
|
|||
|
SyIrql: .space 4 // saved IRQL value
|
|||
|
.space 4 // fill for alignment
|
|||
|
SyRa: .space 8 // saved return address
|
|||
|
SyA0: .space 8 // saved argument registers a0 - a2
|
|||
|
SyA1: .space 8 //
|
|||
|
SyA2: .space 8 //
|
|||
|
SyFrameLength: // length of stack frame
|
|||
|
|
|||
|
NESTED_ENTRY(KeSynchronizeExecution, SyFrameLength, zero)
|
|||
|
|
|||
|
lda sp, -SyFrameLength(sp) // allocate stack frame
|
|||
|
stq ra, SyRa(sp) // save return address
|
|||
|
stq s0, SyS0(sp) // save integer register s0
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
stq a1, SyA1(sp) // save synchronization routine address
|
|||
|
stq a2, SyA2(sp) // save synchronization routine context
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to the synchronization level and acquire the associated
|
|||
|
// spin lock.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
LDP s0, InActualLock(a0) // get address of spin lock
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
ldq_u t1, InSynchronizeIrql(a0) // get synchronization IRQL
|
|||
|
lda t2, InSynchronizeIrql(a0) //
|
|||
|
extbl t1, t2, a0 //
|
|||
|
|
|||
|
SWAP_IRQL // raise IRQL to synchronization level
|
|||
|
|
|||
|
stl v0, SyIrql(sp) // save old irql
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
10: LDP_L t0, 0(s0) // get current lock value
|
|||
|
bis s0, zero, t1 // set lock ownership value
|
|||
|
bne t0, 15f // if ne, spin lock owned
|
|||
|
STP_C t1, 0(s0) // set spin lock owned
|
|||
|
beq t1, 15f // if eq, store conditional failed
|
|||
|
mb // synchronize memory access
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Call specified routine passing the specified context parameter.
|
|||
|
//
|
|||
|
|
|||
|
LDP t5, SyA1(sp) // get synchronize routine address
|
|||
|
LDP a0, SyA2(sp) // get synchronzie routine context
|
|||
|
jsr ra, (t5) // call routine
|
|||
|
|
|||
|
//
|
|||
|
// Release spin lock, lower IRQL to its previous level, and return the value
|
|||
|
// returned by the specified routine.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
mb // synchronize memory access
|
|||
|
STP zero, 0(s0) // set spin lock not owned
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
ldl a0, SyIrql(sp) // get saved IRQL
|
|||
|
extbl a0, 0, a0 // this is a uchar
|
|||
|
bis v0, zero, s0 // save return value
|
|||
|
|
|||
|
SWAP_IRQL // lower IRQL to previous level
|
|||
|
|
|||
|
bis s0, zero, v0 // restore return value
|
|||
|
ldq s0, SyS0(sp) // restore s0
|
|||
|
ldq ra, SyRa(sp) // restore ra
|
|||
|
lda sp, SyFrameLength(sp) // deallocate stack frame
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to acquire lock failed.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
15: LDP t0, 0(s0) // read current lock value
|
|||
|
beq t0, 10b // if lock available, retry spinlock
|
|||
|
br zero, 15b // spin in cache until lock available
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
.end KeSynchronizeExecution
|
|||
|
|
|||
|
SBTTL("Dispatch Chained Interrupt")
|
|||
|
//++
|
|||
|
//
|
|||
|
// 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.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// a0 - Supplies a pointer to the interrupt object.
|
|||
|
//
|
|||
|
// s6/fp - Supplies a pointer to a trap frame.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
.struct 0
|
|||
|
ChS0: .space 8 // saved integer registers s0 - s5
|
|||
|
ChS1: .space 8 //
|
|||
|
ChS2: .space 8 //
|
|||
|
ChS3: .space 8 //
|
|||
|
ChS4: .space 8 //
|
|||
|
ChS5: .space 8 //
|
|||
|
ChRa: .space 8 // saved return address
|
|||
|
ChIrql: .space 4 // saved IRQL value
|
|||
|
ChSpinL: .space 4 // address of spin lock
|
|||
|
ChFrameLength: // length of stack frame
|
|||
|
|
|||
|
NESTED_ENTRY(KiChainedDispatch, ChFrameLength, zero)
|
|||
|
|
|||
|
lda sp, -ChFrameLength(sp) // allocate stack frame
|
|||
|
stq ra, ChRa(sp) // save return address
|
|||
|
stq s0, ChS0(sp) // save integer registers s0 - s6
|
|||
|
stq s1, ChS1(sp) //
|
|||
|
stq s2, ChS2(sp) //
|
|||
|
stq s3, ChS3(sp) //
|
|||
|
stq s4, ChS4(sp) //
|
|||
|
stq s5, ChS5(sp) //
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
// Register usage:
|
|||
|
//
|
|||
|
// s0 = address of listhead
|
|||
|
// s1 = address of current item in list
|
|||
|
// s2 = floating status saved flag
|
|||
|
// s3 = mode of interrupt
|
|||
|
// s4 = irql of interrupt source
|
|||
|
// s5 = synchronization level requested for current list item
|
|||
|
//
|
|||
|
// Initialize loop variables.
|
|||
|
//
|
|||
|
|
|||
|
ADDP a0, InInterruptListEntry, s0 // set address of listhead
|
|||
|
bis s0, zero, s1 // set address of first entry
|
|||
|
bis zero, zero, s2 // clear floating state saved flag
|
|||
|
ldq_u t0, InMode(a0) // get mode of interrupt
|
|||
|
lda t2, InMode(a0) //
|
|||
|
extbl t0, t2, s3 //
|
|||
|
ldq_u t1, InIrql(a0) // get interrupt source IRQL
|
|||
|
lda t3, InIrql(a0) //
|
|||
|
extbl t1, t3, s4 //
|
|||
|
|
|||
|
//
|
|||
|
// Walk the list of connected interrupt objects and call the respective
|
|||
|
// interrupt service routines.
|
|||
|
//
|
|||
|
|
|||
|
10: SUBP s1, InInterruptListEntry, a0 // compute interrupt object address
|
|||
|
ldq_u t2, InFloatingSave(a0) // get floating save flag
|
|||
|
lda t1, InFloatingSave(a0) //
|
|||
|
extbl t2, t1, t0 //
|
|||
|
bne s2, 20f // if ne, floating state already saved
|
|||
|
beq t0, 20f // if eq, don't save floating state
|
|||
|
|
|||
|
//
|
|||
|
// Save volatile floating registers in trap frame.
|
|||
|
//
|
|||
|
|
|||
|
bsr ra, KiSaveVolatileFloatState // save floating state
|
|||
|
ldil s2, 1 // set floating state saved flag
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to synchronization level if synchronization level is not
|
|||
|
// equal to the interrupt source level.
|
|||
|
//
|
|||
|
|
|||
|
20: ldq_u t1, InSynchronizeIrql(a0) // get synchronization IRQL
|
|||
|
lda t2, InSynchronizeIrql(a0) //
|
|||
|
extbl t1, t2, s5 //
|
|||
|
cmpeq s4, s5, t0 // Check if synchronization equals source level?
|
|||
|
bne t0, 25f // if ne[true], IRQL levels are same
|
|||
|
bis s5, zero, a0 // set synchronization IRQL
|
|||
|
|
|||
|
SWAP_IRQL // raise IRQL to synchronization level
|
|||
|
|
|||
|
stl v0, ChIrql(sp) // save old IRQL
|
|||
|
SUBP s1, InInterruptListEntry, a0 // recompute interrupt object address
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// Acquire the service routine spin lock and call the service routine.
|
|||
|
//
|
|||
|
|
|||
|
25: //
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
LDP t5, InActualLock(a0) // get address of spin lock
|
|||
|
30: LDP_L t1, 0(t5) // get current lock value
|
|||
|
bis t5, zero, t2 // set ownership value
|
|||
|
bne t1, 35f // if ne, spin lock owned
|
|||
|
STP_C t2, 0(t5) // set spin lock owned
|
|||
|
beq t2, 35f // if eq, store conditional failed
|
|||
|
mb // synchronize memory access
|
|||
|
STP t5, ChSpinL(sp) // save spin lock address
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
LDP t5, InServiceRoutine(a0) // get address of service routine
|
|||
|
LDP a1, InServiceContext(a0) // get service context
|
|||
|
jsr ra, (t5) // call interrupt service routine
|
|||
|
|
|||
|
//
|
|||
|
// Release the service routine spin lock.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
LDP t5, ChSpinL(sp) // get address of spin lock
|
|||
|
mb // synchronize memory access
|
|||
|
STP zero, 0(t5) // 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.
|
|||
|
//
|
|||
|
|
|||
|
cmpeq s4, s5, t0 // check if synchronization equals source level
|
|||
|
bne t0, 37f // if ne[true], IRQL levels are same
|
|||
|
bis s4, zero, a0 // set interrupt source IRQL
|
|||
|
|
|||
|
SWAP_IRQL // lower to interrupt source IRQL
|
|||
|
|
|||
|
//
|
|||
|
// Get next list entry and check for end of loop.
|
|||
|
//
|
|||
|
|
|||
|
37: LDP s1, LsFlink(s1) // get next interrupt object address
|
|||
|
beq v0, 40f // if eq, interrupt not handled
|
|||
|
beq s3, 50f // if eq, level sensitive interrupt
|
|||
|
40: cmpeq s0, s1, t0 // check if end of list
|
|||
|
beq t0, 10b // if eq[false], not end of list
|
|||
|
|
|||
|
//
|
|||
|
// Either the interrupt is level sensitive and has been handled or the end of
|
|||
|
// the interrupt object chain has been reached. Check to determine if floating
|
|||
|
// machine state needs to be restored.
|
|||
|
//
|
|||
|
|
|||
|
50: beq s2, 60f // if eq, floating state not saved
|
|||
|
|
|||
|
//
|
|||
|
// Restore volatile floating registers from trap frame.
|
|||
|
//
|
|||
|
|
|||
|
bsr ra, KiRestoreVolatileFloatState // restore floating state
|
|||
|
|
|||
|
//
|
|||
|
// Restore integer registers s0 - s5, retrieve return address, deallocate
|
|||
|
// stack frame, and return.
|
|||
|
//
|
|||
|
|
|||
|
60: ldq s0, ChS0(sp) // restore integer registers s0 - s6
|
|||
|
ldq s1, ChS1(sp) //
|
|||
|
ldq s2, ChS2(sp) //
|
|||
|
ldq s3, ChS3(sp) //
|
|||
|
ldq s4, ChS4(sp) //
|
|||
|
ldq s5, ChS5(sp) //
|
|||
|
ldq ra, ChRa(sp) // restore return address
|
|||
|
lda sp, ChFrameLength(sp) // deallocate stack frame
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to acquire spinlock failed.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
35: LDP t1, 0(t5) // read current lock value
|
|||
|
beq t1, 30b // if eq, lock available
|
|||
|
br zero, 35b // spin in cache until lock available
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
.end KiChainedDispatch
|
|||
|
|
|||
|
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.
|
|||
|
//
|
|||
|
// s6/fp - Supplies a pointer to a trap frame.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
.struct 0
|
|||
|
FlS0: .space 8 // saved integer registers s0 - s1
|
|||
|
FlS1: .space 8 //
|
|||
|
FlIrql: .space 4 // saved IRQL value
|
|||
|
.space 4 // for alignment
|
|||
|
FlRa: .space 8 // saved return address
|
|||
|
FlFrameLength: // length of stack frame
|
|||
|
|
|||
|
NESTED_ENTRY(KiFloatingDispatch, FlFrameLength, zero)
|
|||
|
|
|||
|
lda sp, -FlFrameLength(sp) // allocate stack frame
|
|||
|
stq ra, FlRa(sp) // save return address
|
|||
|
stq s0, FlS0(sp) // save integer registers s0 - s1
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
stq s1, FlS1(sp) //
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
// Save volatile floating registers f0 - f19 in trap frame.
|
|||
|
//
|
|||
|
|
|||
|
bsr ra, KiSaveVolatileFloatState // save floating state
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to synchronization level if synchronization level is not
|
|||
|
// equal to the interrupt source level.
|
|||
|
//
|
|||
|
|
|||
|
bis a0, zero, s0 // save address of interrupt object
|
|||
|
ldq_u t2, InSynchronizeIrql(s0) // get synchronization IRQL
|
|||
|
lda t1, InSynchronizeIrql(s0) //
|
|||
|
extbl t2, t1, a0 //
|
|||
|
ldq_u t3, InIrql(s0) // get interrupt source IRQL
|
|||
|
lda t4, InIrql(s0) //
|
|||
|
extbl t3, t4, t0 //
|
|||
|
cmpeq a0, t0, t1 // check if synchronize equals source IRQL ?
|
|||
|
bne t1, 10f // if ne[true], IRQL levels same
|
|||
|
|
|||
|
SWAP_IRQL // raise IRQL to synchronization level
|
|||
|
|
|||
|
stl v0, FlIrql(sp) // save old irql
|
|||
|
10: bis s0, zero, a0 // restore address of interrupt object
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// Acquire the service routine spin lock and call the service routine.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
LDP s1, InActualLock(a0) // get address of spin lock
|
|||
|
20: LDP_L t1, 0(s1) // get current lock value
|
|||
|
bis s1, s1, t2 // set ownership value
|
|||
|
bne t1, 25f // if ne, spin lock owned
|
|||
|
STP_C t2, 0(s1) // set spin lock owned
|
|||
|
beq t2, 25f // if eq, store conditional failed
|
|||
|
mb // synchronize memory access
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
LDP t5, InServiceRoutine(a0) // get address of service routine
|
|||
|
LDP a1, InServiceContext(a0) // get service context
|
|||
|
jsr ra, (t5) // call service routine
|
|||
|
|
|||
|
//
|
|||
|
// Release the service routine spin lock.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
mb // synchronize memory access
|
|||
|
STP 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.
|
|||
|
//
|
|||
|
|
|||
|
ldq_u t3, InIrql(s0) // get interrupt source IRQL
|
|||
|
lda t1, InIrql(s0) //
|
|||
|
extbl t3, t1, a0 //
|
|||
|
ldq_u t4, InSynchronizeIrql(s0) // get synchronization IRQL
|
|||
|
lda t2, InSynchronizeIrql(s0) //
|
|||
|
extbl t4, t2, t0 //
|
|||
|
cmpeq a0, t0, t1 // check if synchronize equal source IRQL?
|
|||
|
bne t1, 30f // if eq, IRQL levels are the same
|
|||
|
|
|||
|
SWAP_IRQL // lower IRQL to interrupt source
|
|||
|
|
|||
|
//
|
|||
|
// Restore volatile floating registers f0 - f19 from trap frame.
|
|||
|
//
|
|||
|
|
|||
|
30: bsr ra, KiRestoreVolatileFloatState // restore floating state
|
|||
|
|
|||
|
//
|
|||
|
// Restore integer registers s0 - s1, retrieve return address, deallocate
|
|||
|
// stack frame, and return.
|
|||
|
//
|
|||
|
|
|||
|
ldq s0, FlS0(sp) // restore integer registers s0 - s1
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
ldq s1, FlS1(sp) //
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
ldq ra, FlRa(sp) // restore return address
|
|||
|
lda sp, FlFrameLength(sp) // deallocate stack frame
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to acquire spinlock failed.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
25: LDP t1, 0(s1) // read current lock value
|
|||
|
beq t1, 20b // if lock available, retry spinlock
|
|||
|
br zero, 25b // spin in cache until lock available
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
.end KiFloatingDispatch
|
|||
|
|
|||
|
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.
|
|||
|
//
|
|||
|
// N.B. This routine raises the interrupt level to the synchronization
|
|||
|
// level specified in the interrupt object.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// a0 - Supplies a pointer to the interrupt object.
|
|||
|
//
|
|||
|
// s6/fp - Supplies a pointer to a trap frame.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
.struct 0
|
|||
|
.space 8 // insure octaword alignment
|
|||
|
RdS0: .space 8 // saved integer registers s0
|
|||
|
RdIrql: .space 4 // saved IRQL value
|
|||
|
.space 4 // for alignment
|
|||
|
RdRa: .space 8 // saved return address
|
|||
|
RdFrameLength: // length of stack frame
|
|||
|
|
|||
|
NESTED_ENTRY(KiInterruptDispatchRaise, RdFrameLength, zero)
|
|||
|
|
|||
|
lda sp, -RdFrameLength(sp) // allocate stack frame
|
|||
|
stq ra, RdRa(sp) // save return address
|
|||
|
stq s0, RdS0(sp) // save integer registers s0
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to synchronization level
|
|||
|
//
|
|||
|
|
|||
|
bis a0, zero, s0 // save address of interrupt object
|
|||
|
ldq_u t3, InSynchronizeIrql(s0) // get synchronization IRQL
|
|||
|
lda t1, InSynchronizeIrql(s0) //
|
|||
|
extbl t3, t1, a0 //
|
|||
|
|
|||
|
SWAP_IRQL // raise IRQL to synchronization level
|
|||
|
|
|||
|
stl v0, RdIrql(sp) // save old irql
|
|||
|
bis s0, zero, a0 // restore address of interrupt object
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// Acquire the service routine spin lock and call the service routine.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
LDP t3, InActualLock(a0) // get address of actual lock
|
|||
|
20: LDP_L t1, 0(t3) // get current lock value
|
|||
|
bis t3, t3, t2 // set lock ownership value
|
|||
|
bne t1, 25f // if ne, spin lock owned
|
|||
|
STP_C t2, 0(t3) // set spin lock owned
|
|||
|
beq t2, 25f // if eq, store conditional failed
|
|||
|
mb // synchronize memory access
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
LDP t5, InServiceRoutine(a0) // get address of service routine
|
|||
|
LDP a1, InServiceContext(a0) // get service context
|
|||
|
jsr ra, (t5) // call service routine
|
|||
|
|
|||
|
//
|
|||
|
// Release the service routine spin lock.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
LDP t2, InActualLock(s0) // get address of actual lock
|
|||
|
mb // synchronize memory access
|
|||
|
STP zero, 0(t2) // set spin lock not owned
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Lower IRQL to the previous level.
|
|||
|
//
|
|||
|
|
|||
|
ldl a0, RdIrql(sp) // get previous IRQL
|
|||
|
|
|||
|
SWAP_IRQL // lower to interrupt source IRQL
|
|||
|
|
|||
|
//
|
|||
|
// Restore integer register s0, retrieve return address, deallocate
|
|||
|
// stack frame, and return.
|
|||
|
//
|
|||
|
|
|||
|
30: ldq s0, RdS0(sp) // restore integer register s0
|
|||
|
ldq ra, RdRa(sp) // restore return address
|
|||
|
lda sp, RdFrameLength(sp) // deallocate stack frame
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to acquire spinlock failed.
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
25: LDP t1, 0(t3) // read current lock value
|
|||
|
beq t1, 20b // if lock available, retry spinlock
|
|||
|
br zero, 25b // spin in cache until lock available
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
.end 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.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// a0 - Supplies a pointer to the interrupt object.
|
|||
|
//
|
|||
|
// s6/fp - Supplies a pointer to a trap frame.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
#if defined(NT_UP)
|
|||
|
|
|||
|
LEAF_ENTRY(KiInterruptDispatchSame)
|
|||
|
|
|||
|
LDP t5, InServiceRoutine(a0) // get address of service routine
|
|||
|
LDP a1, InServiceContext(a0) // get service context
|
|||
|
jsr zero, (t5) // jump to service routine
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
.struct 0
|
|||
|
.space 8 // insure octaword alignment
|
|||
|
SdS0: .space 8 // saved integer registers s0
|
|||
|
SdIrql: .space 4 // saved IRQL value
|
|||
|
.space 4 // for alignment
|
|||
|
SdRa: .space 8 // saved return address
|
|||
|
SdFrameLength: // length of stack frame
|
|||
|
|
|||
|
NESTED_ENTRY(KiInterruptDispatchSame, SdFrameLength, zero)
|
|||
|
|
|||
|
lda sp, -SdFrameLength(sp) // allocate stack frame
|
|||
|
stq ra, SdRa(sp) // save return address
|
|||
|
stq s0, SdS0(sp) // save integer registers s0
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// Acquire the service routine spin lock and call the service routine.
|
|||
|
//
|
|||
|
|
|||
|
LDP t3, InActualLock(a0) // get actual lock address
|
|||
|
bis a0, zero, s0 // save interrupt object address
|
|||
|
20: LDP_L t1, 0(t3) // get current lock value
|
|||
|
bis t3, t3, t2 // set lock ownership value
|
|||
|
bne t1, 25f // if ne, spin lock owned
|
|||
|
STP_C t2, 0(t3) // set spin lock owned
|
|||
|
beq t2, 25f // if eq, store conditional failed
|
|||
|
mb // synchronize memory access
|
|||
|
LDP t5, InServiceRoutine(a0) // get address of service routine
|
|||
|
LDP a1, InServiceContext(a0) // get service context
|
|||
|
jsr ra, (t5) // call service routine
|
|||
|
|
|||
|
//
|
|||
|
// Release the service routine spin lock.
|
|||
|
//
|
|||
|
|
|||
|
LDP t2, InActualLock(s0) // get actual lock address
|
|||
|
mb // synchronize memory access
|
|||
|
STP zero, 0(t2) // set spin lock not owned
|
|||
|
|
|||
|
//
|
|||
|
// Restore integer registers s0, retrieve return address, deallocate
|
|||
|
// stack frame, and return.
|
|||
|
//
|
|||
|
|
|||
|
30: ldq s0, SdS0(sp) // restore integer register s0
|
|||
|
ldq ra, SdRa(sp) // restore return address
|
|||
|
lda sp, SdFrameLength(sp) // deallocate stack frame
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to acquire spinlock failed.
|
|||
|
//
|
|||
|
|
|||
|
25: LDP t1, 0(t3) // read current lock value
|
|||
|
beq t1, 20b // if lock available, retry spinlock
|
|||
|
br zero, 25b // spin in cache until lock available
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
.end KiInterruptDispatchSame
|
|||
|
|
|||
|
SBTTL("Interrupt Template")
|
|||
|
//++
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine is a template that is copied into each interrupt object. Its
|
|||
|
// function is to determine the address of the respective interrupt object
|
|||
|
// and then transfer control to the appropriate interrupt dispatcher.
|
|||
|
//
|
|||
|
// N.B. On entry to this routine only the volatile integer registers have
|
|||
|
// been saved.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// a0 - Supplies a pointer to the interrupt template within an interrupt
|
|||
|
// object.
|
|||
|
//
|
|||
|
// s6/fp - Supplies a pointer to a trap frame.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiInterruptTemplate)
|
|||
|
|
|||
|
.set noreorder
|
|||
|
.set noat
|
|||
|
LDP t5, InDispatchAddress - InDispatchCode(a0) // get dispatcher address
|
|||
|
SUBP a0, InDispatchCode, a0 // compute address of interrupt object
|
|||
|
jmp zero, (t5) // transfer to dispatch routine
|
|||
|
bis zero, zero, zero // nop for alignment
|
|||
|
.set at
|
|||
|
.set reorder
|
|||
|
|
|||
|
.end KiInterruptTemplate
|
|||
|
|
|||
|
SBTTL("Disable Interrupts")
|
|||
|
//++
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine disables interrupts on the current processor and
|
|||
|
// returns the previous state of the interrrupt enable bit.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// A boolean value, if true interrupts were previously turned on,
|
|||
|
// false indicates interrupts were previously off.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiDisableInterrupts)
|
|||
|
|
|||
|
GET_CURRENT_PROCESSOR_STATUS_REGISTER // get current prcb address
|
|||
|
|
|||
|
DISABLE_INTERRUPTS // disable interrupts
|
|||
|
|
|||
|
and v0, PSR_IE_MASK, v0 // isolate interrupt enable
|
|||
|
srl v0, PSR_IE, v0 // shift to bit 0
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
.end KiDisableInterrupts
|
|||
|
|
|||
|
SBTTL("Restore Interrupts")
|
|||
|
//++
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine enables interrupts according to the the previous
|
|||
|
// interrupt enable passed as input.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// a0 - Supplies previous interrupt enable state (returned by
|
|||
|
// KiDisableInterrupts)
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiRestoreInterrupts)
|
|||
|
|
|||
|
beq a0, 10f // if eq, then interrupts disabled
|
|||
|
|
|||
|
ENABLE_INTERRUPTS // enable interrupts
|
|||
|
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
10: DISABLE_INTERRUPTS // disable interrupts
|
|||
|
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
.end KiRestoreInterrupts
|
|||
|
|
|||
|
SBTTL("Unexpected Interrupts")
|
|||
|
//++
|
|||
|
//
|
|||
|
// 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.
|
|||
|
//
|
|||
|
// N.B. - This routine relies upon a private convention with the
|
|||
|
// interrupt exception dispatcher that register t12 contains the
|
|||
|
// interrupt vector of the unexpected interrupt. This convention
|
|||
|
// will only work if the first level dispatch causes the
|
|||
|
// unexpected interrupt.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// a0 - Supplies a pointer to the interrupt object.
|
|||
|
// t12 - Supplies the interrupt vector.
|
|||
|
//
|
|||
|
// s6/fp - Supplies a pointer to a trap frame.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
.struct 0
|
|||
|
.space 8 // filler for 16 byte alignment
|
|||
|
UiRa: .space 8 // return address
|
|||
|
UiFrameLength: // frame length
|
|||
|
|
|||
|
NESTED_ENTRY(KiUnexpectedInterrupt, UiFrameLength, zero)
|
|||
|
|
|||
|
lda sp, -UiFrameLength(sp) // allocate stack frame
|
|||
|
stq ra, UiRa(sp) // save return address
|
|||
|
|
|||
|
PROLOGUE_END //
|
|||
|
|
|||
|
ldil a0, 0xfacefeed // ****** temp ******
|
|||
|
bis t12, zero, a1 // pass interrupt vector
|
|||
|
bis zero, zero, a2 // zero remaining parameters
|
|||
|
bis zero, zero, a3 //
|
|||
|
bis zero, zero, a4 //
|
|||
|
bis zero, zero, a5 //
|
|||
|
bsr ra, KeBugCheckEx // perform system crash
|
|||
|
|
|||
|
.end KiUnexpectedInterrupt
|
|||
|
|
|||
|
SBTTL(KiPassiveRelease)
|
|||
|
//++
|
|||
|
//
|
|||
|
// RoutineDescription:
|
|||
|
//
|
|||
|
// KiPassiveRelease passively releases an interrupt that cannot/will not
|
|||
|
// be serviced at this time. Or there is no reason to service it and
|
|||
|
// maybe this routine will never be called in a million years.
|
|||
|
//
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY( KiPassiveRelease )
|
|||
|
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
.end KiPassiveRelease
|
|||
|
|