863 lines
29 KiB
ArmAsm
863 lines
29 KiB
ArmAsm
// TITLE("Interrupt Support")
|
||
//++
|
||
//
|
||
// Copyright (c) 1995 Microsoft Corporation and IBM Corporation
|
||
//
|
||
// Module Name:
|
||
//
|
||
// xxintsup.s
|
||
//
|
||
// Abstract:
|
||
//
|
||
// This module implements the PowerPC machine dependent code for
|
||
// interrupt handling.
|
||
//
|
||
// Author:
|
||
//
|
||
// Chuck Lenzmeier (chuckl) 18-Feb-1995
|
||
// Adapter from C code by Peter L. Johnston (plj@vnet.ibm.com) August 1993
|
||
// Adapted from code by David N. Cutler (davec) 1-Apr-1991
|
||
//
|
||
// Environment:
|
||
//
|
||
// Kernel mode only, IRQL DISPATCH_LEVEL.
|
||
//
|
||
// Revision History:
|
||
//
|
||
//--
|
||
|
||
#include "ksppc.h"
|
||
|
||
.extern __imp_KeLowerIrql
|
||
.extern __imp_KeRaiseIrql
|
||
|
||
#if !defined(NT_UP) && SPINDBG1
|
||
.extern ..KiAcquireSpinLockDbg
|
||
#endif
|
||
|
||
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 (r3) - Supplies a pointer to a control object of type interrupt.
|
||
//
|
||
// SynchronizeRoutine (r4) - 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 (r5) - 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
|
||
.space StackFrameHeaderLength
|
||
kseLR: .space 4
|
||
kseR31: .space 4
|
||
kseR4: .space 4
|
||
kseR5: .space 4
|
||
kseIrql: .space 4
|
||
kseToc: .space 4
|
||
.align 3 // ensure 8 byte alignment
|
||
kseFrameLength:
|
||
|
||
//
|
||
// N.B. We are a bit footloose with the TOC pointer in this routine.
|
||
// We do not restore it immediately after the call to KeRaiseIrql,
|
||
// and only restore it on return from the synchronize routine. (And
|
||
// we only restore it then because the call to KeLowerIrql needs it.)
|
||
//
|
||
|
||
SPECIAL_ENTRY_S(KeSynchronizeExecution,_TEXT$00)
|
||
|
||
mflr r0 // get return address
|
||
stwu sp, -kseFrameLength(sp) // allocate stack frame
|
||
stw r31, kseR31(sp)
|
||
stw r0, kseLR(sp) // save return address
|
||
|
||
PROLOGUE_END(KeSynchronizeExecution)
|
||
|
||
stw r4, kseR4(sp) // save synchronization routine address
|
||
lwz r6, [toc]__imp_KeRaiseIrql(rtoc) // &&function descriptor
|
||
stw r5, kseR5(sp) // save synchronization routine context
|
||
lwz r6, 0(r6) // &function descriptor
|
||
stw rtoc, kseToc(sp) // save our TOC
|
||
lwz r5, 0(r6) // &KeRaiseIrql
|
||
|
||
//
|
||
// Raise IRQL to the synchronization level and acquire the associated
|
||
// spin lock.
|
||
//
|
||
|
||
#if !defined(NT_UP)
|
||
lwz r31, InActualLock(r3) // get address of spin lock
|
||
#endif
|
||
|
||
lwz rtoc, 4(r6) // HAL's TOC
|
||
lbz r3, InSynchronizeIrql(r3) // get synchronization IRQL
|
||
mtctr r5
|
||
addi r4, sp, kseIrql // compute address to save IRQL
|
||
bctrl
|
||
// N.B. skip restoring the TOC
|
||
|
||
lwz r4, kseR4(sp) // get synchronize routine descriptor
|
||
|
||
#if !defined(NT_UP)
|
||
ACQUIRE_SPIN_LOCK(r31, r31, r5, kse_lock, kse_lock_spin)
|
||
#endif
|
||
|
||
//
|
||
// Call specified routine passing the specified context parameter.
|
||
//
|
||
lwz r5, 0(r4) // get synchronize routine address
|
||
lwz rtoc, 4(r4) // get synchronize routine TOC
|
||
mtctr r5 // put routine address in CTR
|
||
lwz r3, kseR5(sp) // get synchronize routine context
|
||
bctrl // call specified routine
|
||
|
||
//
|
||
// Release spin lock, lower IRQL to its previous level, and return the value
|
||
// returned by the specified routine.
|
||
//
|
||
|
||
lwz rtoc, kseToc(sp) // restore our TOC
|
||
#if !defined(NT_UP)
|
||
li r5, 0 // get a 0 for spin lock
|
||
#endif
|
||
lwz r6, [toc]__imp_KeLowerIrql(rtoc) // &&function descriptor
|
||
#if !defined(NT_UP)
|
||
RELEASE_SPIN_LOCK(r31, r5)
|
||
#endif
|
||
lwz r6, 0(r6) // &function descriptor
|
||
ori r31, r3, 0 // save return value
|
||
lwz r5, 0(r6) // &KeLowerIrql
|
||
|
||
lbz r3, kseIrql(sp) // get saved IRQL
|
||
mtctr r5
|
||
lwz rtoc, 4(r6) // HAL's TOC
|
||
bctrl
|
||
lwz rtoc, kseToc(sp) // restore our TOC
|
||
|
||
ori r3, r31, 0 // set return value
|
||
|
||
lwz r0, kseLR(sp) // get return address
|
||
lwz r31, kseR31(sp) // restore r31
|
||
mtlr r0 // set return address
|
||
addi sp, sp, kseFrameLength // return stack frame
|
||
|
||
blr
|
||
|
||
#if !defined(NT_UP)
|
||
SPIN_ON_SPIN_LOCK(r31, r5, kse_lock, kse_lock_spin)
|
||
#endif
|
||
|
||
DUMMY_EXIT(KeSynchronizeExecution)
|
||
|
||
SBTTL("Chained Dispatch")
|
||
//++
|
||
//
|
||
// VOID
|
||
// KiChainedDispatch (
|
||
// IN PKINTERRUPT Interrupt,
|
||
// IN PVOID ServiceContext,
|
||
// IN PVOID TrapFrame
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This routine is entered as a 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.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Interrupt (r3) - Supplies a pointer to the Interrupt Object.
|
||
//
|
||
// ServiceContext (r4) - Supplies a pointer to the Service Context associated
|
||
// with this Interrupt Object.
|
||
//
|
||
// TrapFrame (r5) - Supplies the address of the Trap Frame created as a
|
||
// result of this interrupt.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
.struct 0
|
||
.space StackFrameHeaderLength
|
||
kcdLR: .space 4
|
||
#if !defined(NT_UP)
|
||
kcdR24: .space 4
|
||
#endif
|
||
kcdR25: .space 4
|
||
kcdR26: .space 4
|
||
kcdR27: .space 4
|
||
kcdR28: .space 4
|
||
kcdR29: .space 4
|
||
kcdR30: .space 4
|
||
kcdR31: .space 4
|
||
kcdIrql: .space 4
|
||
kcdToc: .space 4
|
||
.align 3 // ensure 8 byte alignment
|
||
kcdFrameLength:
|
||
|
||
//
|
||
// N.B. We are a bit footloose with the TOC pointer in this routine.
|
||
// We only ensure the TOC is correct when we explicitly need it
|
||
// to be correct. We do not restore it on exit. This is safe
|
||
// because we know that our caller called us via a function
|
||
// descriptor and will therefore restore its own TOC when we return.
|
||
//
|
||
|
||
SPECIAL_ENTRY(KiChainedDispatch)
|
||
|
||
mflr r0 // get return address
|
||
stwu sp, -kcdFrameLength(sp) // allocate stack frame
|
||
#if !defined(NT_UP)
|
||
stw r24, kcdR24(sp)
|
||
#endif
|
||
stw r25, kcdR25(sp)
|
||
stw r26, kcdR26(sp)
|
||
stw r27, kcdR27(sp)
|
||
stw r28, kcdR28(sp)
|
||
stw r29, kcdR29(sp)
|
||
stw r30, kcdR30(sp)
|
||
stw r31, kcdR31(sp)
|
||
stw r0, kcdLR(sp) // save return address
|
||
|
||
PROLOGUE_END(KiChainedDispatch)
|
||
|
||
ori r25, r5, 0 // save trap frame address
|
||
stw rtoc, kcdToc(sp) // save our TOC
|
||
|
||
//
|
||
// Initialize loop variables.
|
||
//
|
||
|
||
addi r31, r3, InInterruptListEntry // set address of listhead
|
||
ori r30, r31, 0 // set address of first entry
|
||
li r29, 0 // clear floating state saved flag
|
||
lbz r28, InMode(r3) // get mode of interrupt
|
||
lbz r27, InIrql(r3) // get interrupt source IRQL
|
||
|
||
//
|
||
// Walk the list of connected interrupt objects and call the respective
|
||
// interrupt service routines.
|
||
//
|
||
|
||
kcd10:
|
||
|
||
lbz r8, InFloatingSave(r3) // get floating save flag
|
||
cmpwi r29, 0 // floating state already saved?
|
||
cmpwi cr7, r8, 0 // interrupt uses floating state?
|
||
bne kcd20 // if ne, floating state already saved
|
||
beq cr7, kcd20 // if eq, don't save floating state
|
||
|
||
//
|
||
// Save volatile floating registers in trap frame.
|
||
//
|
||
|
||
li r29, 1 // set floating state saved flag
|
||
SAVE_VOLATILE_FLOAT_STATE(r25) // save volatile floating state
|
||
|
||
kcd20:
|
||
|
||
//
|
||
// Raise IRQL to synchronization level if synchronization level is not
|
||
// equal to the interrupt source level.
|
||
//
|
||
|
||
lbz r26, InSynchronizeIrql(r3) // get synchronization IRQL
|
||
cmpw r27, r26 // IRQL levels the same?
|
||
beq kcd25 // if eq, IRQL levels are the same
|
||
|
||
lwz r6, [toc]__imp_KeRaiseIrql(rtoc) // &&function descriptor
|
||
ori r3, r26, 0 // set synchronization IRQL
|
||
lwz r6, 0(r6) // &function descriptor
|
||
addi r4, sp, kcdIrql // compute address to save IRQL
|
||
lwz r5, 0(r6) // &KeRaiseIrql
|
||
lwz rtoc, 4(r6) // HAL's TOC
|
||
mtctr r5
|
||
bctrl
|
||
// N.B. skip restoring the TOC
|
||
|
||
subi r3, r30, InInterruptListEntry // recompute interrupt object address
|
||
|
||
kcd25:
|
||
|
||
lwz r5, InServiceRoutine(r3) // get service routine descriptor
|
||
|
||
//
|
||
// Acquire the service routine spin lock and call the service routine.
|
||
//
|
||
|
||
#if !defined(NT_UP)
|
||
|
||
lwz r24, InActualLock(r3) // get address of spin lock
|
||
ACQUIRE_SPIN_LOCK(r24, r24, r7, kcd_lock, kcd_lock_spin)
|
||
#endif
|
||
|
||
lwz r6, 0(r5) // get address of service routine
|
||
lwz rtoc, 4(r5) // get service routine TOC
|
||
mtctr r6 // put routine address in CTR
|
||
lwz r4, InServiceContext(r3) // get service context
|
||
ori r5, r25, 0 // pass &TrapFrame
|
||
bctrl // call service routine
|
||
|
||
//
|
||
// Release the service routine spin lock. Lower IRQL to the interrupt source
|
||
// level if synchronization level is not the same as the interrupt source level.
|
||
//
|
||
|
||
lwz rtoc, kcdToc(sp) // restore our TOC
|
||
#if !defined(NT_UP)
|
||
li r4, 0 // get a 0 for spin lock
|
||
#endif
|
||
cmpw r27, r26 // IRQL levels the same?
|
||
#if !defined(NT_UP)
|
||
RELEASE_SPIN_LOCK(r24, r4)
|
||
#endif
|
||
ori r26, r3, 0 // save service routine status
|
||
beq kcd35 // if eq, IRQL levels are the same
|
||
|
||
lwz r6, [toc]__imp_KeLowerIrql(rtoc) // &&function descriptor
|
||
ori r3, r27, 0 // set interrupt source IRQL
|
||
lwz r6, 0(r6) // &function descriptor
|
||
lwz r5, 0(r6) // &KeLowerIrql
|
||
lwz rtoc, 4(r6) // HAL's TOC
|
||
mtctr r5
|
||
bctrl
|
||
lwz rtoc, kcdToc(sp) // restore our TOC (for next loop)
|
||
|
||
kcd35:
|
||
|
||
//
|
||
// Get next list entry and check for end of loop.
|
||
//
|
||
|
||
lwz r30, LsFlink(r30) // get next interrupt object address
|
||
cmpwi r26, 0 // interrupt handled?
|
||
cmpwi cr7, r28, 0 // level sensitive interrupt?
|
||
cmpw cr6, r30, r31 // end of list?
|
||
beq kcd40 // if eq, interrupt not handled
|
||
beq cr7,kcd50 // if eq, level sensitive interrupt
|
||
kcd40:
|
||
subi r3, r30, InInterruptListEntry // compute interrupt object address
|
||
bne cr6,kcd10 // if ne, not end of list
|
||
kcd50:
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
cmpwi r29, 0 // floating state saved?
|
||
beq kcd60 // if eq, floating state not saved
|
||
|
||
//
|
||
// Restore volatile floating registers from trap frame.
|
||
//
|
||
|
||
RESTORE_VOLATILE_FLOAT_STATE(r25) // restore volatile floating state
|
||
|
||
kcd60:
|
||
|
||
//
|
||
// Restore nonvolatile registers, retrieve return address, deallocate
|
||
// stack frame, and return.
|
||
//
|
||
|
||
lwz r0, kcdLR(sp) // get return address
|
||
lwz r31, kcdR31(sp) // restore r31
|
||
lwz r30, kcdR30(sp) // restore r30
|
||
lwz r29, kcdR29(sp) // restore r29
|
||
lwz r28, kcdR28(sp) // restore r28
|
||
lwz r27, kcdR27(sp) // restore r27
|
||
lwz r26, kcdR26(sp) // restore r26
|
||
lwz r25, kcdR25(sp) // restore r25
|
||
#if !defined(NT_UP)
|
||
lwz r24, kcdR24(sp) // restore r24
|
||
#endif
|
||
mtlr r0 // set return address
|
||
addi sp, sp, kcdFrameLength // return stack frame
|
||
|
||
blr
|
||
|
||
#if !defined(NT_UP)
|
||
SPIN_ON_SPIN_LOCK(r24, r7, kcd_lock, kcd_lock_spin)
|
||
#endif
|
||
|
||
DUMMY_EXIT(KiChainedDispatch)
|
||
|
||
SBTTL("Floating Dispatch")
|
||
//++
|
||
//
|
||
// VOID
|
||
// KiFloatingDispatch (
|
||
// IN PKINTERRUPT Interrupt,
|
||
// IN PVOID ServiceContext,
|
||
// IN PVOID TrapFrame
|
||
// )
|
||
//
|
||
// 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:
|
||
//
|
||
// Interrupt (r3) - Supplies a pointer to the Interrupt Object.
|
||
//
|
||
// ServiceContext (r4) - Supplies a pointer to the Service Context associated
|
||
// with this Interrupt Object.
|
||
//
|
||
// TrapFrame (r5) - Supplies the address of the Trap Frame created as a
|
||
// result of this interrupt.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
.struct 0
|
||
.space StackFrameHeaderLength
|
||
kfdLR: .space 4
|
||
#if !defined(NT_UP)
|
||
kfdR29: .space 4
|
||
#endif
|
||
kfdR30: .space 4
|
||
kfdR31: .space 4
|
||
kfdIrql: .space 4
|
||
kfdToc: .space 4
|
||
.align 3 // ensure 8 byte alignment
|
||
kfdFrameLength:
|
||
|
||
//
|
||
// N.B. We are a bit footloose with the TOC pointer in this routine.
|
||
// We only ensure the TOC is correct when we explicitly need it
|
||
// to be correct. We do not restore it on exit. This is safe
|
||
// because we know that our caller called us via a function
|
||
// descriptor and will therefore restore its own TOC when we return.
|
||
//
|
||
|
||
SPECIAL_ENTRY(KiFloatingDispatch)
|
||
|
||
mflr r0 // get return address
|
||
stwu sp, -kfdFrameLength(sp) // allocate stack frame
|
||
#if !defined(NT_UP)
|
||
stw r29, kfdR29(sp)
|
||
#endif
|
||
stw r30, kfdR30(sp)
|
||
stw r31, kfdR31(sp)
|
||
stw r0, kfdLR(sp) // save return address
|
||
|
||
PROLOGUE_END(KiFloatingDispatch)
|
||
|
||
ori r30, r5, 0 // save trap frame address
|
||
stw rtoc, kfdToc(sp) // save our TOC
|
||
|
||
//
|
||
// Save volatile floating registers in trap frame.
|
||
//
|
||
|
||
SAVE_VOLATILE_FLOAT_STATE(r5) // save volatile floating state
|
||
|
||
//
|
||
// Raise IRQL to synchronization level if synchronization level is not
|
||
// equal to the interrupt source level.
|
||
//
|
||
|
||
ori r31, r3, 0 // save address of interrupt object
|
||
lbz r4, InIrql(r3) // get interrupt source IRQL
|
||
lbz r8, InSynchronizeIrql(r3) // get synchronization IRQL
|
||
cmpw r8, r4 // IRQL levels the same?
|
||
beq kfd10 // if eq, IRQL levels are the same
|
||
|
||
lwz r6, [toc]__imp_KeRaiseIrql(rtoc) // &&function descriptor
|
||
ori r3, r8, 0 // set synchronization IRQL
|
||
lwz r6, 0(r6) // &function descriptor
|
||
addi r4, sp, kfdIrql // compute address to save IRQL
|
||
lwz r8, 0(r6) // &KeLowerIrql
|
||
lwz rtoc, 4(r6) // HAL's TOC
|
||
mtctr r8
|
||
bctrl
|
||
// N.B. skip restoring the TOC
|
||
|
||
ori r3, r31, 0 // restore address of interrupt object
|
||
|
||
kfd10:
|
||
|
||
lwz r8, InServiceRoutine(r31) // get service routine descriptor
|
||
|
||
//
|
||
// Acquire the service routine spin lock and call the service routine.
|
||
//
|
||
|
||
#if !defined(NT_UP)
|
||
lwz r29, InActualLock(r31) // get address of spin lock
|
||
ACQUIRE_SPIN_LOCK(r29, r29, r7, kfd_lock, kfd_lock_spin)
|
||
#endif
|
||
|
||
lwz r6, 0(r8) // get address of service routine
|
||
lwz rtoc, 4(r8) // get service routine TOC
|
||
mtctr r6 // put routine address in CTR
|
||
lwz r4, InServiceContext(r31) // get service context
|
||
bctrl // call service routine
|
||
|
||
//
|
||
// Release the service routine spin lock. Lower IRQL to the interrupt source
|
||
// level if synchronization level is not the same as the interrupt source level.
|
||
//
|
||
|
||
lwz rtoc, kfdToc(sp) // restore our TOC
|
||
#if !defined(NT_UP)
|
||
li r6, 0 // get a 0 for spin lock
|
||
#endif
|
||
lbz r3, InIrql(r31) // get interrupt source IRQL
|
||
lbz r4, InSynchronizeIrql(r31) // get synchronization IRQL
|
||
#if !defined(NT_UP)
|
||
RELEASE_SPIN_LOCK(r29, r6)
|
||
#endif
|
||
cmpw r3, r4 // IRQL levels the same?
|
||
beq kfd30 // if eq, IRQL levels are the same
|
||
|
||
lwz r6, [toc]__imp_KeLowerIrql(rtoc) // &&function descriptor
|
||
lwz r6, 0(r6) // &function descriptor
|
||
lwz r5, 0(r6) // &KeLowerIrql
|
||
lwz rtoc, 4(r6) // HAL's TOC
|
||
mtctr r5
|
||
bctrl
|
||
|
||
kfd30:
|
||
|
||
//
|
||
// Restore volatile floating registers from trap frame.
|
||
//
|
||
|
||
RESTORE_VOLATILE_FLOAT_STATE(r30) // restore volatile floating state
|
||
|
||
//
|
||
// Restore nonvolatile registers, retrieve return address, deallocate
|
||
// stack frame, and return.
|
||
//
|
||
|
||
lwz r0, kfdLR(sp) // get return address
|
||
#if !defined(NT_UP)
|
||
lwz r29, kfdR29(sp) // restore r29
|
||
#endif
|
||
lwz r30, kfdR30(sp) // restore r30
|
||
lwz r31, kfdR31(sp) // restore r31
|
||
mtlr r0 // set return address
|
||
addi sp, sp, kfdFrameLength // return stack frame
|
||
|
||
blr
|
||
|
||
#if !defined(NT_UP)
|
||
SPIN_ON_SPIN_LOCK(r29, r7, kfd_lock, kfd_lock_spin)
|
||
#endif
|
||
|
||
DUMMY_EXIT(KiFloatingDispatch)
|
||
|
||
SBTTL("Interrupt Dispatch - Raise IRQL")
|
||
//++
|
||
//
|
||
// VOID
|
||
// KiInterruptDispatchRaise (
|
||
// IN PKINTERRUPT Interrupt,
|
||
// IN PVOID ServiceContext,
|
||
// IN PVOID TrapFrame
|
||
// )
|
||
//
|
||
// 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. This routine raises the interrupt level to the synchronization
|
||
// level specified in the interrupt object.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Interrupt (r3) - Supplies a pointer to the Interrupt Object.
|
||
//
|
||
// ServiceContext (r4) - Supplies a pointer to the Service Context associated
|
||
// with this Interrupt Object.
|
||
//
|
||
// TrapFrame (r5) - Supplies the address of the Trap Frame created as a
|
||
// result of this interrupt.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
.struct 0
|
||
.space StackFrameHeaderLength
|
||
kidrLR: .space 4
|
||
kidrR31: .space 4
|
||
kidrIrql: .space 4
|
||
kidrToc: .space 4
|
||
.align 3 // ensure 8 byte alignment
|
||
kidrFrameLength:
|
||
|
||
//
|
||
// N.B. We are a bit footloose with the TOC pointer in this routine.
|
||
// We only ensure the TOC is correct when we explicitly need it
|
||
// to be correct. We do not restore it on exit. This is safe
|
||
// because we know that our caller called us via a function
|
||
// descriptor and will therefore restore its own TOC when we return.
|
||
//
|
||
|
||
SPECIAL_ENTRY(KiInterruptDispatchRaise)
|
||
|
||
mflr r0 // get return address
|
||
stwu sp, -kidrFrameLength(sp) // allocate stack frame
|
||
stw r31, kidrR31(sp)
|
||
lwz r6, [toc]__imp_KeRaiseIrql(rtoc) // &&function descriptor
|
||
stw r0, kidrLR(sp) // save return address
|
||
|
||
PROLOGUE_END(KiInterruptDispatchRaise)
|
||
|
||
lwz r6, 0(r6) // &function descriptor
|
||
stw rtoc, kidrToc(sp) // save our TOC
|
||
|
||
//
|
||
// Raise IRQL to synchronization level.
|
||
//
|
||
|
||
lwz r8, 0(r6) // &KeRaiseIrql
|
||
ori r31, r3, 0 // save address of interrupt object
|
||
lwz rtoc, 4(r6) // HAL's TOC
|
||
lbz r3, InSynchronizeIrql(r3) // get synchronization IRQL
|
||
mtctr r8
|
||
addi r4, sp, kidrIrql // compute address to save IRQL
|
||
bctrl
|
||
// N.B. skip restoring the TOC
|
||
|
||
lwz r8, InServiceRoutine(r31) // get service routine descriptor
|
||
ori r3, r31, 0 // restore address of interrupt object
|
||
lwz r4, InServiceContext(r31) // get service context
|
||
|
||
//
|
||
// Acquire the service routine spin lock and call the service routine.
|
||
//
|
||
|
||
lwz r6, 0(r8) // get address of service routine
|
||
|
||
#if !defined(NT_UP)
|
||
lwz r31, InActualLock(r31) // get address of spin lock
|
||
ACQUIRE_SPIN_LOCK(r31, r31, r7, kidr_lock, kidr_lock_spin)
|
||
#endif
|
||
|
||
mtctr r6 // put routine address in CTR
|
||
lwz rtoc, 4(r8) // get service routine TOC
|
||
bctrl // call service routine
|
||
|
||
//
|
||
// Release the service routine spin lock. Lower IRQL to the previous level.
|
||
//
|
||
|
||
lwz rtoc, kidrToc(sp) // restore our TOC
|
||
#if !defined(NT_UP)
|
||
li r4, 0 // get a 0 for spin lock
|
||
#endif
|
||
lwz r6, [toc]__imp_KeLowerIrql(rtoc) // &&function descriptor
|
||
#if !defined(NT_UP)
|
||
RELEASE_SPIN_LOCK(r31, r4)
|
||
#endif
|
||
lwz r6, 0(r6) // &function descriptor
|
||
lwz r8, 0(r6) // &KeLowerIrql
|
||
lwz rtoc, 4(r6) // HAL's TOC
|
||
mtctr r8
|
||
lbz r3,kidrIrql(sp) // get previous IRQL
|
||
bctrl
|
||
// N.B. skip restoring the TOC
|
||
|
||
//
|
||
// Restore nonvolatile registers, retrieve return address, deallocate
|
||
// stack frame, and return.
|
||
//
|
||
|
||
lwz r0, kidrLR(sp) // get return address
|
||
lwz r31, kidrR31(sp) // restore r31
|
||
mtlr r0 // set return address
|
||
addi sp, sp, kidrFrameLength // return stack frame
|
||
|
||
blr
|
||
|
||
#if !defined(NT_UP)
|
||
SPIN_ON_SPIN_LOCK(r31, r7, kidr_lock, kidr_lock_spin)
|
||
#endif
|
||
|
||
DUMMY_EXIT(KiInterruptDispatchRaise)
|
||
|
||
SBTTL("Interrupt Dispatch - Same IRQL")
|
||
//++
|
||
//
|
||
// VOID
|
||
// KiInterruptDispatchSame (
|
||
// IN PKINTERRUPT Interrupt,
|
||
// IN PVOID ServiceContext,
|
||
// IN PVOID TrapFrame
|
||
// )
|
||
//
|
||
// 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.
|
||
//
|
||
// Note: On PowerPC, if uniprocessor, this routine is bypassed completely.
|
||
// The Interrupt Object is initialized such that KiInterruptException will
|
||
// dispatch directly to the service routine.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Interrupt (r3) - Supplies a pointer to the Interrupt Object.
|
||
//
|
||
// ServiceContext (r4) - Supplies a pointer to the Service Context associated
|
||
// with this Interrupt Object.
|
||
//
|
||
// TrapFrame (r5) - Supplies the address of the Trap Frame created as a
|
||
// result of this interrupt.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
.struct 0
|
||
.space StackFrameHeaderLength
|
||
kidsLR: .space 4
|
||
kidsR31: .space 4
|
||
.align 3 // ensure 8 byte alignment
|
||
kidsFrameLength:
|
||
|
||
//
|
||
// N.B. We do not save/restore the TOC pointer in this routine.
|
||
// This is safe because our caller called us via a function
|
||
// descriptor and will therefore restore the TOC when we return.
|
||
//
|
||
|
||
#if defined(NT_UP)
|
||
|
||
LEAF_ENTRY(KiInterruptDispatchSame)
|
||
|
||
lwz r8, InServiceRoutine(r3) // get service routine descriptor
|
||
lwz r6, 0(r8) // get address of service routine
|
||
lwz rtoc, 4(r8) // get service routine TOC
|
||
mtctr r6 // put routine address in CTR
|
||
lwz r4, InServiceContext(r3) // get service context
|
||
bctr // jump to service routine
|
||
|
||
DUMMY_EXIT(KiInterruptDispatchSame)
|
||
|
||
#else
|
||
|
||
SPECIAL_ENTRY(KiInterruptDispatchSame)
|
||
|
||
mflr r0 // get return address
|
||
stwu sp, -kidsFrameLength(sp) // allocate stack frame
|
||
stw r31, kidsR31(sp)
|
||
stw r0, kidsLR(sp) // save return address
|
||
|
||
PROLOGUE_END(KiInterruptDispatchSame)
|
||
|
||
lwz r8, InServiceRoutine(r3) // get service routine descriptor
|
||
|
||
//
|
||
// Acquire the service routine spin lock and call the service routine.
|
||
//
|
||
|
||
lwz r31, InActualLock(r3) // get address of spin lock
|
||
lwz r6, 0(r8) // get address of service routine
|
||
ACQUIRE_SPIN_LOCK(r31, r31, r7, kids_lock, kids_lock_spin)
|
||
|
||
lwz rtoc, 4(r8) // get service routine TOC
|
||
mtctr r6 // put routine address in CTR
|
||
lwz r4, InServiceContext(r3) // get service context
|
||
bctrl // call service routine
|
||
|
||
//
|
||
// Release the service routine spin lock. Restore nonvolatile registers,
|
||
// retrieve return address, deallocate stack frame, and return.
|
||
//
|
||
|
||
li r4, 0 // get a 0 for spin lock
|
||
lwz r0, kidsLR(sp) // get return address
|
||
RELEASE_SPIN_LOCK(r31, r4)
|
||
lwz r31, kidsR31(sp) // restore r31
|
||
mtlr r0 // set return address
|
||
addi sp, sp, kidsFrameLength // return stack frame
|
||
|
||
blr
|
||
|
||
SPIN_ON_SPIN_LOCK(r31, r7, kids_lock, kids_lock_spin)
|
||
|
||
DUMMY_EXIT(KiInterruptDispatchSame)
|
||
|
||
#endif // else defined(NT_UP)
|
||
|
||
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.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Interrupt (r3) - Supplies a pointer to the Interrupt Object.
|
||
//
|
||
// ServiceContext (r4) - Supplies a pointer to the Service Context associated
|
||
// with this Interrupt Object.
|
||
//
|
||
// TrapFrame (r5) - Supplies the address of the Trap Frame created as a
|
||
// result of this interrupt.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(KiUnexpectedInterrupt)
|
||
|
||
LEAF_EXIT(KiUnexpectedInterrupt) // ****** temp ******
|