640 lines
24 KiB
ArmAsm
640 lines
24 KiB
ArmAsm
// TITLE("Interval and Profile Clock Interrupts")
|
||
//++
|
||
//
|
||
// Copyright (c) 1990 Microsoft Corporation
|
||
//
|
||
// Module Name:
|
||
//
|
||
// xxclock.s
|
||
//
|
||
// Abstract:
|
||
//
|
||
// This module implements the code necessary to field and process the
|
||
// interval and profile clock interrupts.
|
||
//
|
||
// Author:
|
||
//
|
||
// Chris P. Karamatas 27-Sep-1993
|
||
//
|
||
// Based on MIPS version by David N. Cutler (davec) 27-Mar-1990
|
||
//
|
||
// Modified by:
|
||
//
|
||
// Pat Carr 14-Apr-1994 to follow 3.5 model
|
||
// Peter Johnston 30-May-1994 extensive mods for level 612
|
||
// Peter Johnston 10-Jun-1994 updated to level 683 (Beta 2)
|
||
//
|
||
// Environment:
|
||
//
|
||
// Kernel mode only.
|
||
//
|
||
// Revision History:
|
||
//
|
||
//--
|
||
.file "clock.s"
|
||
|
||
#include "ksppc.h"
|
||
|
||
|
||
//
|
||
// Define external variables used by this module.
|
||
//
|
||
|
||
.extern KeTickCount // 3 * 4
|
||
.extern KeTimeAdjustment // 4
|
||
.extern KiAdjustDpcThreshold // 4
|
||
.extern KiIdealDpcRate // 4
|
||
.extern KiMaximumDpcQueueDepth // 4
|
||
.extern KiProfileListHead // 2 * 4
|
||
.extern KiProfileLock // 4
|
||
.extern KiTimerTableListHead
|
||
.extern KiTimerExpireDpc
|
||
.extern KiTickOffset
|
||
.extern KeMaximumIncrement
|
||
|
||
#if !defined(NT_UP) && SPINDBG
|
||
.extern ..KiAcquireSpinLockDbg
|
||
#endif
|
||
|
||
|
||
//++
|
||
//
|
||
// VOID
|
||
// KeUpdateSystemTime (
|
||
// IN PKTRAP_FRAME TrapFrame
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This routine is entered as the result of an interrupt generated by the
|
||
// interval timer. Its function is to update the system time and check to
|
||
// determine if a timer has expired.
|
||
//
|
||
// N.B. This routine is executed on a single processor in a multiprocess
|
||
// system. The remainder of the processors only execute the quantum end
|
||
// and runtime update code.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// TrapFrame (r.3) - Supplies a pointer to a trap frame.
|
||
// TimeIncrement (r.4) - Supplies the rime increment in 100ns units.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
// rem hal calls this with interrupts disabled
|
||
|
||
.set cr.5.gt, 21
|
||
.set cr.0.gt, 1
|
||
|
||
LEAF_ENTRY(KeUpdateSystemTime)
|
||
|
||
//
|
||
// Update the interrupt time.
|
||
//
|
||
// N.B. The interrupt time is updated in a very strict manner so that an
|
||
// interlock does not have to be used in an MP system.
|
||
//
|
||
|
||
lwz r.5, [toc]KiTickOffset(r.toc) // get addr of globals used
|
||
// from "Compute next tick
|
||
lwz r.12, [toc]KeMaximumIncrement(r.toc) // offset value."
|
||
lwz r.7, KiPcr2 + Pc2InterruptTime + 0(r.0) // get low interrupt time
|
||
lwz r.8, KiPcr2 + Pc2InterruptTime + 4(r.0) // get high interrupt time
|
||
lwz r.10, [toc]KeTickCount(r.toc)
|
||
lwz r.11, [toc]KiTimerTableListHead(r.toc)
|
||
|
||
lwz r.9, 0(r.5) // get tick offset value
|
||
lwz r.12, 0(r.12) // get maximum increment value
|
||
addc r.7, r.7, r.4 // add time increment value
|
||
addze r.8, r.8 // increment high interupt time
|
||
|
||
stw r.8, KiPcr2 + Pc2InterruptTime + 8(r.0) // store high 2 interrupt time
|
||
stw r.7, KiPcr2 + Pc2InterruptTime + 0(r.0) // store low interrupt time
|
||
stw r.8, KiPcr2 + Pc2InterruptTime + 4(r.0) // store high 1 interrupt time
|
||
|
||
sub. r.9, r.9, r.4 // subtract time increment
|
||
// from "Compute next tick
|
||
lwz r.4, [toc]KeTimeAdjustment(r.toc) // offset value."
|
||
stw r.9, 0(r.5) // store tick offset value
|
||
add r.9, r.12, r.9 // add maximum inc to residue
|
||
crmove cr.5.gt, cr.0.gt // save cr.0 gt for later
|
||
lwz r.6, 0(r.10) // get low tick count
|
||
bgt check_timer // jif tick not completed
|
||
|
||
//
|
||
// Compute next tick offset value.
|
||
//
|
||
stw r.9, 0(r.5) // store tick offset value
|
||
lwz r.4, 0(r.4) // get time adjustment value
|
||
|
||
//
|
||
// Update system time.
|
||
//
|
||
// N.B. The system time is updated in a very strict manner so that an
|
||
// interlock does not have to be used in an MP system.
|
||
//
|
||
|
||
lwz r.0, KiPcr2 + Pc2SystemTime + 0(r.0) // get low system time
|
||
lwz r.9, KiPcr2 + Pc2SystemTime + 4(r.0) // get high system time
|
||
addc r.0, r.4, r.0 // add time increment
|
||
// From "Update the tick count"
|
||
lwz r.4, 4(r.10) // get high tick count
|
||
addze r.9, r.9 // incremnt high system time
|
||
|
||
stw r.9, KiPcr2 + Pc2SystemTime + 8(r.0) // store high 2 system time
|
||
stw r.0, KiPcr2 + Pc2SystemTime + 0(r.0) // store low system time
|
||
stw r.9, KiPcr2 + Pc2SystemTime + 4(r.0) // store high 1 system time
|
||
// From "Update the tick count"
|
||
addic r.9, r.6, 1 // increment tick count
|
||
|
||
//
|
||
// Update the tick count.
|
||
//
|
||
// N.B. The tick count is updated in a very strict manner so that an
|
||
// interlock does not have to be used in an MP system.
|
||
//
|
||
|
||
addze r.4, r.4 // increment high word
|
||
stw r.9, KiPcr2 + Pc2TickCountLow(r.0) // store low tick count
|
||
stw r.4, 8(r.10) // store high 2 tick count
|
||
stw r.9, 0(r.10) // store low tick count
|
||
stw r.4, 4(r.10) // store high 1 tick count
|
||
|
||
//
|
||
// Check to determine if a timer has expired at the current (ie old) hand
|
||
// value.
|
||
//
|
||
rlwinm r.10, r.6, 3, (TIMER_TABLE_SIZE - 1) << 3 // get table offset
|
||
add r.10, r.11, r.10 // get addr of table entry
|
||
lwz r.9, LsFlink(r.10) // get addr of 1st timer in list
|
||
cmplw cr7, r.9, r.10 // list empty?
|
||
// From "Get the expiration..."
|
||
lwz r.4, TiDueTime + TmHighTime - TiTimerListEntry(r.9)
|
||
// From "Get the expiration..."
|
||
lwz r.5, TiDueTime + TmLowTime - TiTimerListEntry(r.9)
|
||
beq cr7, check_next_hand // jif yes
|
||
|
||
//
|
||
// Get the expiration time from the timer object.
|
||
//
|
||
// N.B. The offset to the timer list entry must be subtracted out of the
|
||
// displacement calculation.
|
||
//
|
||
cmplw cr.6, r.4, r.8 // check high time
|
||
cmplw cr.7, r.5, r.7 // check low time
|
||
bgt cr.6, check_next_hand // this timer has not expired
|
||
blt cr.6, expire // this timer has expired
|
||
ble cr.7, expire // this timer has expired
|
||
|
||
//
|
||
// Check to determine if a timer has expired at the next hand value.
|
||
//
|
||
check_next_hand:
|
||
addi r.6, r.6, 1 // advance hand entry to next
|
||
check_timer:
|
||
rlwinm r.10, r.6, 3, (TIMER_TABLE_SIZE - 1) << 3 // get table offset
|
||
add r.10, r.11, r.10 // get addr of table entry
|
||
lwz r.9, LsFlink(r.10) // get addr of 1st timer in list
|
||
cmplw cr.7, r.9, r.10 // list empty?
|
||
lwz r.5, TiDueTime + TmLowTime - TiTimerListEntry(r.9)
|
||
beq cr.7, kust_exit // jif yes
|
||
|
||
// Get the expiration time from the timer object.
|
||
//
|
||
// N.B. The offset to the timer list entry must be subtracted out of the
|
||
// displacement calculation.
|
||
//
|
||
// Note we can't move this guy
|
||
// above beq kust_exit.
|
||
lwz r.4, TiDueTime + TmHighTime - TiTimerListEntry(r.9)
|
||
cmplw cr.6, r.4, r.8 // check high time
|
||
cmplw cr.7, r.5, r.7 // check low time
|
||
bgt cr.6, kust_exit // this timer has not expired
|
||
blt cr.6, expire // this timer has expired
|
||
bgt cr.7, kust_exit // this timer has not expired
|
||
|
||
//
|
||
// Put timer expiration DPC in the system DPC list and initiate a dispatch
|
||
// interrupt on the current processor.
|
||
//
|
||
|
||
expire:
|
||
lwz r.9, KiPcr+PcPrcb(r.0) // get address of PRCB
|
||
lwz r.10, [toc]KiTimerExpireDpc(r.toc)// get expiration DPC address
|
||
addi r.11, r.9, PbDpcListHead // compute DPC listhead address
|
||
addi r.7, r.9, PbDpcLock // compute DPC lock address
|
||
|
||
#if !defined(NT_UP)
|
||
ACQUIRE_SPIN_LOCK(r.7, r.11, r.0, expire_lock, expire_lock_spin)
|
||
#endif
|
||
|
||
lwz r.8, DpLock(r.10) // get DPC inserted state
|
||
addi r.5, r.10, DpDpcListEntry // compute addr DPC list entry
|
||
lwz r.12, LsBlink(r.11) // get addr last entry in list
|
||
cmplwi r.8, 0 // DPC inserted?
|
||
bne queued // jif DPC already inserted
|
||
lwz r.8, PbDpcQueueDepth(r.9) // get DPC queue depth
|
||
stw r.7, DpLock(r.10) // set DPC inserted state
|
||
stw r.6, DpSystemArgument1(r.10) // set timer table hand value
|
||
|
||
stw r.5, LsBlink(r.11) // set addr of new last entry
|
||
stw r.5, LsFlink(r.12) // set next in old last entry
|
||
stw r.11, LsFlink(r.5) // set address of next entry
|
||
stw r.12, LsBlink(r.5) // set address of previous entry
|
||
|
||
addi r.8, r.8, 1 // increment DPC queue depth
|
||
stw r.8, PbDpcQueueDepth(r.9) //
|
||
|
||
SOFTWARE_INTERRUPT(DISPATCH_LEVEL, r.4)
|
||
|
||
queued:
|
||
|
||
#if !defined(NT_UP)
|
||
RELEASE_SPIN_LOCK(r.7, r.0)
|
||
#endif
|
||
|
||
kust_exit:
|
||
|
||
ble cr.5, ..KeUpdateRunTime // if lez, full tick
|
||
|
||
blr
|
||
|
||
#if !defined(NT_UP)
|
||
SPIN_ON_SPIN_LOCK(r.7, r.0, expire_lock, expire_lock_spin)
|
||
#endif
|
||
|
||
DUMMY_EXIT(KeUpdateSystemTime)
|
||
|
||
|
||
//++
|
||
//
|
||
// VOID
|
||
// KeUpdateRunTime (
|
||
// IN PKTRAP_FRAME TrapFrame
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This routine is entered as the result of an interrupt generated by the
|
||
// interval timer. Its function is to update the runtime of the current
|
||
// thread, update the runtime of the current thread's process, and decrement
|
||
// the current thread's quantum.
|
||
//
|
||
// N.B. This routine is executed on all processors in a multiprocess system.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// TrapFrame (r.3) - Supplies a pointer to a trap frame.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(KeUpdateRunTime)
|
||
|
||
lwz r.9, KiPcr+PcPrcb(r.0) // get current processor block
|
||
lwz r.7, TrMsr(r.3) // get saved machine status
|
||
// From "If a DPC is activ..."
|
||
lbz r.10, TrOldIrql(r.3) // get previous IRQL
|
||
lwz r.4, KiPcr+PcCurrentThread(r.0) // get current thread address
|
||
lwz r.8, ThUserTime(r.4) // get user time
|
||
lwz r.11, PbDpcRoutineActive(r.9) // get DPC active flag
|
||
extrwi. r.7, r.7, 1, MSR_PR // test previous mode
|
||
lwz r.6, ThApcState + AsProcess(r.4)// get addr current process
|
||
cmpwi cr.1, r.11, 0 // DPC active ?
|
||
bne user // jif previous mode was user
|
||
|
||
//
|
||
// If a DPC is active, then increment the time spent executing DPC routines.
|
||
// Otherwise, if the old IRQL is greater than DPC level, then increment the
|
||
// time spent executing interrupt services routines. Otherwise, increment
|
||
// the time spent in kernel mode for the current thread.
|
||
//
|
||
|
||
lwz r.11, ThKernelTime(r.4) // get kernel time
|
||
cmpwi r.10, DISPATCH_LEVEL // compare IRQL with DPC level
|
||
addi r.7, r.9, PbInterruptTime // compute interrupt time addr
|
||
blt kernel // if ltz, inc. thread kernel time
|
||
bgt intrpt // if >DPC level bump interrupt
|
||
addi r.7, r.9, PbDpcTime // compute DPC time address
|
||
beq cr.1, kernel // jif not dpc active
|
||
|
||
//
|
||
// Update the time spent in DPC/interrupt processing.
|
||
//
|
||
|
||
intrpt:
|
||
lwz r.8, 0(r.7) // get processor time
|
||
addi r.5, r.9, PbKernelTime // compute processor kernel time addr.
|
||
addi r.8, r.8, 1 // increment processor time
|
||
stw r.8, 0(r.7) // store processor time
|
||
b processor
|
||
|
||
//
|
||
// Update the time spent in kernel mode for the current thread.
|
||
//
|
||
|
||
kernel:
|
||
addi r.6, r.6, PrKernelTime // compute process kernel time addr.
|
||
addi r.5, r.9, PbKernelTime // compute processor kernel time addr.
|
||
addi r.11, r.11, 1 // increment kernel time
|
||
stw r.11, ThKernelTime(r.4) // store kernel time
|
||
b continue
|
||
|
||
//
|
||
// Update the time spent in user mode for the current thread.
|
||
//
|
||
|
||
user:
|
||
addi r.6, r.6, PrUserTime // compute process user time addr.
|
||
addi r.5, r.9, PbUserTime // compute processor user time addr.
|
||
addi r.8, r.8, 1 // increment user time
|
||
stw r.8, ThUserTime(r.4) // store user time
|
||
|
||
//
|
||
// Update the time spent in kernel/user mode for the current thread's process.
|
||
//
|
||
// N.B. The update of the process time must be synchronized across processors.
|
||
//
|
||
|
||
//DBGSTORE_I(r10,r8,0x1112)
|
||
continue:
|
||
lwarx r.10, 0, r.6 // get process time
|
||
addi r.10, r.10, 1 // increment process time
|
||
stwcx. r.10, 0, r.6 // store process time
|
||
bne- continue // if store conditional failed
|
||
|
||
//
|
||
// Update the time spent in kernel/user mode for the current processor.
|
||
//
|
||
|
||
processor:
|
||
lwz r.10, 0(r.5) // get low processor time
|
||
|
||
//
|
||
// Update the DPC request rate which is computed as the average between
|
||
// the previous rate and the current rate.
|
||
//
|
||
|
||
lwz r.8, PbDpcQueueDepth(r.9) // get current DPC queue depth
|
||
lwz r.6, PbDpcLastCount(r.9) // get last DPC count
|
||
lwz r.7, PbDpcRequestRate(r.9)// get last DPC request rate
|
||
lwz r.0, PbDpcInterruptRequested(r.9)// interrupt requested?
|
||
// NOTE: we can't move these below
|
||
// the next lwz to r.5
|
||
addi r.10, r.10, 1 // increment processor time
|
||
stw r.10, 0(r.5) // store low processor time
|
||
lwz r.5, PbDpcCount(r.9) // get current DPC count
|
||
cmpwi cr.0, r.8, 0
|
||
lwz r.8, [toc]KiAdjustDpcThreshold(r.toc)
|
||
stw r.5, PbDpcLastCount(r.9) // set last DPC count
|
||
sub r.5, r.5, r.6 // compute count during interval
|
||
cmpwi cr.7, r.0, 0 // interrupt requested ?
|
||
add r.5, r.5, r.7 // compute sum of current and last
|
||
srwi r.5, r.5, 1 // average current and last
|
||
stw r.5, PbDpcRequestRate(r.9)// set new DPC request rate
|
||
lwz r.0, 0(r.8) // get DPC threshold counter
|
||
lwz r.7, PbMaximumDpcQueueDepth(r.9)// get current max queue depth
|
||
|
||
//
|
||
// If the current DPC queue depth is not zero, a DPC routine is not active,
|
||
// and a DPC interrupt has not been requested, then request a dispatch
|
||
// interrupt, decrement the maximum DPC queue depth, and reset the threshold
|
||
// counter if appropriate.
|
||
//
|
||
|
||
bne cr.1, nodpc // jif DPC routine active
|
||
beq cr.0, nodpc // jif DPC queue is empty
|
||
bne cr.7, nodpc // jif DPC already requested
|
||
|
||
lwz r.6, [toc]KiIdealDpcRate(r.toc) // get &ideal DPC rate
|
||
stw r.0, PbAdjustDpcThreshold(r.9) // set new DPC threshold counter
|
||
lwz r.6, 0(r.6) // get ideal DPC rate
|
||
li r.0, 1
|
||
stb r.0, KiPcr+PcDispatchInterrupt(r.0) // request DPC interrupt
|
||
cmpw cr.6, r.5, r.6 // current rate < ideal ?
|
||
subic. r.7, r.7, 1 // decrement max DPC queue depth
|
||
bge cr.6, ..KiDecrementQuantum // jif rate >= ideal
|
||
beq ..KiDecrementQuantum // if cur val == 1
|
||
stw r.7, PbMaximumDpcQueueDepth(r.9)// set new maximum queue depth
|
||
b ..KiDecrementQuantum
|
||
|
||
//
|
||
// The DPC queue is empty or a DPC routine is active or a DPC interrupt
|
||
// has been requested. Count down the adjustment threshold and if the
|
||
// count reaches zero, then increment the maximum DPC queue depth, but
|
||
// no above the initial value and reset the adjustment threshold value.
|
||
//
|
||
|
||
nodpc:
|
||
lwz r.5, [toc]KiMaximumDpcQueueDepth(r.toc)
|
||
lwz r.6, PbAdjustDpcThreshold(r.9) // get adjustment threshold
|
||
lwz r.5, 0(r.5) // get init max queue depth
|
||
subic. r.6, r.6, 1 // decrement adjustment
|
||
stw r.6, PbAdjustDpcThreshold(r.9) // threshold counter
|
||
bne ..KiDecrementQuantum
|
||
cmpw cr.6, r.5, r.7
|
||
stw r.0, PbAdjustDpcThreshold(r.9) // reset threshold
|
||
beq cr.6, ..KiDecrementQuantum // jif at max depth
|
||
addi r.7, r.7, 1 // increment current max depth
|
||
stw r.7, PbMaximumDpcQueueDepth(r.9)// set new maximum DPC queue
|
||
// depth.
|
||
|
||
|
||
|
||
//
|
||
// Decrement current thread quantum and check to determine if a quantum end
|
||
// has occurred.
|
||
//
|
||
|
||
ALTERNATE_ENTRY(KiDecrementQuantum)
|
||
|
||
lbz r.5, ThQuantum(r.4) // get current thread quantum
|
||
extsb r.5, r.5 // sign-extend thread quantum
|
||
subic. r.5, r.5, CLOCK_QUANTUM_DECREMENT // decrement current quantum
|
||
stb r.5, ThQuantum(r.4) // store thread quantum
|
||
bgtlr+ // return if quantum remaining
|
||
|
||
//
|
||
// Set quantum end flag and initiate a dispatch interrupt on the current
|
||
// processor.
|
||
//
|
||
|
||
lwz r.5, PbIdleThread(r.9) // get address of idle thread
|
||
cmpw r.5, r.4 // is this the idle thread?
|
||
beqlr- // return if in idle thread
|
||
|
||
stw r.sp, KiPcr+PcQuantumEnd(r.0) // set quantum end indicator
|
||
|
||
SOFTWARE_INTERRUPT(DISPATCH_LEVEL, r.8)
|
||
|
||
LEAF_EXIT(KeUpdateRunTime)
|
||
|
||
//++
|
||
//
|
||
// VOID
|
||
// KeProfileInterruptWithSource (
|
||
// IN PKTRAP_FRAME TrapFrame,
|
||
// IN KPROFILE_SOURCE ProfileSource
|
||
// )
|
||
//
|
||
// VOID
|
||
// KeProfileInterrupt (
|
||
// IN PKTRAP_FRAME TrapFrame
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This routine is entered as the result of an interrupt generated by the
|
||
// profile timer. Its function is to update the profile information for
|
||
// the currently active profile objects.
|
||
//
|
||
// N.B. This routine is executed on all processors in a multiprocess system.
|
||
//
|
||
// N.B. KeProfileInterruptWithSource currently not implemented
|
||
//
|
||
// Arguments:
|
||
//
|
||
// TrapFrame (r.3) - Supplies a pointer to a trap frame.
|
||
//
|
||
// ProfileSource (r.4) - Supplies the source of the profile interrupt
|
||
// KeProfileInterrupt is an alternate entry for backwards
|
||
// compatibility that sets the source to zero (ProfileTime)
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
.struct 0
|
||
.space StackFrameHeaderLength
|
||
piLR: .space 4 // Link Register
|
||
.align 3 // 8 byte align
|
||
piFrameLength:
|
||
|
||
SPECIAL_ENTRY(KeProfileInterrupt)
|
||
|
||
li r.4, 0 // set profile source to
|
||
// ProfileTime
|
||
|
||
ALTERNATE_ENTRY(KeProfileInterruptWithSource)
|
||
|
||
mflr r.0
|
||
stwu r.sp, -piFrameLength(r.sp)
|
||
stw r.0, piLR(r.sp) // save return address
|
||
|
||
PROLOGUE_END(KeProfileInterrupt)
|
||
|
||
#if !defined(NT_UP)
|
||
|
||
lwz r.11, [toc]KiProfileLock(r.toc)
|
||
|
||
#endif
|
||
|
||
#if !defined(NT_UP)
|
||
ACQUIRE_SPIN_LOCK(r.11, r.3, r.10, profile_lock, profile_lock_spin)
|
||
#endif
|
||
|
||
lwz r.5, KiPcr+PcCurrentThread(r.0) // get current thread address
|
||
lwz r.5, ThApcState + AsProcess(r.5)// get current process address
|
||
addi r.5, r.5, PrProfileListHead // compute profile listhead addr
|
||
bl ..KiProcessProfileList // process process profile list
|
||
lwz r.5, [toc]KiProfileListHead(r.toc)// get profile listhead addr
|
||
bl ..KiProcessProfileList // process system profile list
|
||
|
||
lwz r.0, piLR(r.sp) // get return address
|
||
|
||
#if !defined(NT_UP)
|
||
lwz r.11, [toc]KiProfileLock(r.toc)
|
||
li r.10, 0
|
||
RELEASE_SPIN_LOCK(r.11, r.10)
|
||
#endif
|
||
|
||
mtlr r.0 // set return address
|
||
addi r.sp, r.sp, piFrameLength // deallocate stack frame
|
||
|
||
blr
|
||
|
||
#if !defined(NT_UP)
|
||
SPIN_ON_SPIN_LOCK(r.11, r.10, profile_lock, profile_lock_spin)
|
||
#endif
|
||
|
||
DUMMY_EXIT(KeProfileInterrupt)
|
||
|
||
//++
|
||
//
|
||
// VOID
|
||
// KiProcessProfileList (
|
||
// IN PKTRAP_FRAME TrapFrame,
|
||
// IN KPROFILE_SOURCE Source,
|
||
// IN PLIST_ENTRY ListHead
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This routine is called to process a profile list.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// TrapFrame (r.3) - Supplies a pointer to a trap frame.
|
||
//
|
||
// Source (r.4) - Supplies profile source to match
|
||
//
|
||
// ListHead (r.5) - Supplies a pointer to a profile list.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
// Note:
|
||
//
|
||
// Registers r.3 and r.4 are returned unaltered.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(KiProcessProfileList)
|
||
|
||
lwz r.6, LsFlink(r.5) // get address of next entry
|
||
cmplw r.5, r.6 // cmp process profile list head
|
||
beqlr // if eq, end of list
|
||
lwz r.12, KiPcr+PcPrcb(r.0) // get address of PRCB
|
||
lwz r.7, TrIar(r.3) // get interrupt PC address
|
||
lwz r.12, PbSetMember(r.12) // get current processor num
|
||
|
||
//
|
||
// Scan profile list and increment profile buckets as appropriate.
|
||
//
|
||
|
||
l.10: lhz r.0, PfSource - PfProfileListEntry(r.6) // get source
|
||
lwz r.8, PfRangeBase - PfProfileListEntry(r.6) // get range base
|
||
cmplw cr.6, r.0, r.4 // compare source
|
||
lwz r.9, PfRangeLimit - PfProfileListEntry(r.6)// get range limit
|
||
lwz r.11, PfAffinity - PfProfileListEntry(r.6) // get affinity
|
||
bne cr.6, l.20 // if ne, source mismatch
|
||
cmplw cr.7, r.7, r.8 // check against range base
|
||
cmplw cr.1, r.7, r.9 // check against range limit
|
||
and. r.11, r.11, r.12 // check affinity
|
||
blt cr.7, l.20 // jif less than range base
|
||
bgt cr.1, l.20 // jif not less than range limit
|
||
beq cr.0, l.20 // jif affinity mismatch
|
||
sub r.8, r.7, r.8 // compute offset in range
|
||
lwz r.9, PfBucketShift - PfProfileListEntry(r.6)// get shift count
|
||
lwz r.10, PfBuffer - PfProfileListEntry(r.6) // get &profile buffer
|
||
srw r.8, r.8, r.9 // compute bucket offset
|
||
rlwinm r.8, r.8, 0, 0xfffffffc // clear low order offset bits
|
||
lwzx r.7, r.8, r.10 // increment profile bucket
|
||
addi r.7, r.7, 1 //
|
||
stwx r.7, r.8, r.10 //
|
||
l.20: lwz r.6, LsFlink(r.6) // get address of next entry
|
||
cmplw r.5, r.6 // more entries in list ?
|
||
bne l.10 // jif yes
|
||
|
||
LEAF_EXIT(KiProcessProfileList)
|
||
|