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 ******
|