mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
637 lines
23 KiB
637 lines
23 KiB
// r TITLE("Interval and Profile Clock Interrupts")
|
|
//++
|
|
//
|
|
// Copyright (c) 1990 Microsoft Corporation
|
|
// Copyright (c) 1992 Digital Equipment Corporation
|
|
//
|
|
// Module Name:
|
|
//
|
|
// clock.s
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This module implements the code necessary to field and process the
|
|
// interval and profile clock interrupts.
|
|
//
|
|
// Author:
|
|
//
|
|
// David N. Cutler (davec) 27-Mar-1990
|
|
// Joe Notarangelo 06-Apr-1992
|
|
//
|
|
// Environment:
|
|
//
|
|
// Kernel mode only.
|
|
//
|
|
// Revision History:
|
|
//
|
|
//--
|
|
|
|
#include "ksalpha.h"
|
|
|
|
|
|
//++
|
|
//
|
|
// VOID
|
|
// KeUpdateSystemTime (
|
|
// IN PKTRAP_FRAME TrapFrame,
|
|
// IN ULONG TimeIncrement
|
|
// )
|
|
//
|
|
// 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 (a0) - Supplies a pointer to a trap frame.
|
|
//
|
|
// Time Increment (a1) - Supplies the time increment in 100ns units.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(KeUpdateSystemTime)
|
|
|
|
//
|
|
// Update the interrupt time.
|
|
//
|
|
|
|
zap a1, 0xf0, a1 // zero extend time increment
|
|
lda a2, KiTickOffset // get tick offset value
|
|
ldl a3, 0(a2) //
|
|
ldil t8, SharedUserData // get shared user data address
|
|
ldq t9, UsInterruptTime(t8) //
|
|
addq a1, t9, t9 // add time increment value
|
|
stq t9, UsInterruptTime(t8) // store interrupt time value
|
|
subq a3, a1, a3 // subtract time increment
|
|
lda v0, KeTickCount // get tick count value
|
|
ldq t6, 0(v0) //
|
|
lda t0, KiTimerTableListHead // get base address of timer table
|
|
stl a3, 0(a2) // store tick offset value
|
|
bgt a3, 10f // if gt, tick not completed
|
|
ldl a4, KeMaximumIncrement // get maximum increment value
|
|
|
|
//
|
|
// Update system time.
|
|
//
|
|
|
|
lda t1, KeTimeAdjustment // get time adjustment value
|
|
ldl t1, 0(t1) //
|
|
ldq t3, UsSystemTime(t8) // get system time value
|
|
addq t1, t3, t3 // add time increment value
|
|
stq t3, UsSystemTime(t8) // store system time value
|
|
|
|
//
|
|
// Update the tick count.
|
|
//
|
|
|
|
addq t6, 1, t1 // increment tick count value
|
|
stq t1, 0(v0) // store tick count value
|
|
stl t1, UsTickCountLow(t8)
|
|
|
|
//
|
|
// Compute next tick offset value.
|
|
//
|
|
|
|
addq a3, a4, a4 // add maximum increment to residue
|
|
stl a4, 0(a2) // store tick offset value
|
|
|
|
//
|
|
// Check to determine if a timer has expired at the current hand value.
|
|
//
|
|
|
|
and t6, TIMER_TABLE_SIZE - 1, v0 // reduce to table table index
|
|
s8addl v0, t0, t2 // compute timer table listhead address
|
|
ldl t3, LsFlink(t2) // get address of first timer in list
|
|
cmpeq t2, t3, t4 // compare fist with listhead address
|
|
bne t4, 5f // if ne, no timer active
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
ldq t4,TiDueTime - TiTimerListEntry(t3) // get due time
|
|
cmpule t4, t9, t5 // is expiration time <= system time
|
|
bne t5, 20f // if ne, timer has expired
|
|
|
|
//
|
|
// Check to determine if a timer has expired at the next hand value.
|
|
//
|
|
|
|
5: addq t6, 1, t6 // advance hand value to next entry
|
|
10: and t6, TIMER_TABLE_SIZE - 1, v0 // reduce to table table index
|
|
s8addl v0, t0, t2 // compute timer table listhead address
|
|
ldl t3, LsFlink(t2) // get address of first timer in list
|
|
cmpeq t2, t3, t4 // compare fist with listhead address
|
|
bne t4, 40f // if ne, no timer active
|
|
|
|
//
|
|
// Get the expiration time from the timer object.
|
|
//
|
|
|
|
ldq t4, TiDueTime - TiTimerListEntry(t3) // get due time
|
|
cmpule t4, t9, t5 // is expiration time <= system time
|
|
beq t5, 40f // if eq, timer has not expired
|
|
|
|
//
|
|
// Put timer expiration DPC in the system DPC list and initiate a dispatch
|
|
// interrupt on the current processor.
|
|
//
|
|
|
|
20: lda t2, KiTimerExpireDpc // get expiration DPC address
|
|
|
|
DISABLE_INTERRUPTS // turn off interrupts
|
|
|
|
GET_PROCESSOR_CONTROL_BLOCK_BASE // v0 = base address of PRCB
|
|
|
|
lda t3, PbDpcListHead(v0) // get DPC listhead address
|
|
lda t1, PbDpcLock(v0) // get address of spin lock
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
30: ldl_l t4, 0(t1) // get current lock value
|
|
bis t1, zero, t5 // set ownership value
|
|
bne t4, 50f // if ne, spin lock owned
|
|
stl_c t5, 0(t1) // set spin lock owned
|
|
beq t5, 50f // if eq, store conditional failed
|
|
mb // synchronize subsequent reads after
|
|
// the spinlock is acquired
|
|
#endif
|
|
|
|
ldl t4, DpLock(t2) // get DPC inserted state
|
|
bne t4, 35f // if ne, DPC entry already inserted
|
|
ldl t4, LsBlink(t3) // get address of last entry in list
|
|
stl t1, DpLock(t2) // set DPC inserted state
|
|
stl t6, DpSystemArgument1(t2) // set timer table hand value
|
|
addl t2, DpDpcListEntry, t2 // compute address of DPC list entry
|
|
stl t2, LsBlink(t3) // set address of new last entry
|
|
stl t2, LsFlink(t4) // set next link in old last entry
|
|
stl t3, LsFlink(t2) // set address of next entry
|
|
stl t4, LsBlink(t2) // set address of previous entry
|
|
ldl t5, PbDpcQueueDepth(v0) // get current DPC queue depth
|
|
addl t5, 1, t7 // increment DPC queue depth
|
|
stl t7, PbDpcQueueDepth(v0) // set updated DPC queue depth
|
|
|
|
//
|
|
// N.B. Since an interrupt must be active, simply set the software interrupt
|
|
// request bit in the PRCB to request a dispatch interrupt directly from
|
|
// the interrupt exception handler.
|
|
//
|
|
|
|
ldil t11, DISPATCH_INTERRUPT // a0 = level of interrupt to request
|
|
stl t11, PbSoftwareInterrupts(v0) // request a DISPATCH sfw interrupt
|
|
35:
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
mb // insure all previous writes go
|
|
// before the lock is released
|
|
stl zero, 0(t1) // set spin lock not owned
|
|
|
|
#endif
|
|
|
|
ENABLE_INTERRUPTS
|
|
|
|
40:
|
|
|
|
ble a3, KeUpdateRunTime // if le, full tick
|
|
ret zero, (ra) // return
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
50: ldl t4, 0(t1) // get lock value
|
|
beq t4, 30b // retry spinlock if now available
|
|
br zero, 50b // retry in cache until lock ready
|
|
|
|
#endif
|
|
|
|
.end 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 (a0) - Supplies a pointer to a trap frame.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(KeUpdateRunTime)
|
|
GET_CURRENT_THREAD // v0 = current thread address
|
|
bis v0, zero, t0 // t0 = current thread address
|
|
GET_PROCESSOR_CONTROL_BLOCK_BASE // v0 = processor block address
|
|
bis v0, zero, t5 // t5 = processor block address
|
|
|
|
//
|
|
// Update the current DPC rate.
|
|
//
|
|
// A running average of the DPC rate is used. The number of DPCs requested
|
|
// in the previous tick is added to the current DPC rate and divided by two.
|
|
// This becomes the new DPC rate.
|
|
//
|
|
ldl t1, PbDpcCount(t5) // get current DPC count
|
|
ldl t6, PbLastDpcCount(t5) // get last DPC count
|
|
subl t1, t6, t7 // compute difference
|
|
ldl t2, PbDpcRequestRate(t5) // get old DPC request rate
|
|
addl t7, t2, t3 // compute average
|
|
srl t3, 1, t4 //
|
|
stl t4, PbDpcRequestRate(t5) // store new DPC request rate
|
|
stl t1, PbLastDpcCount(t5) // update last DPC count
|
|
|
|
ldl t2, ThApcState + AsProcess(t0) // get address of current proc
|
|
ldl t3, TrPsr(a0) // get saved processor status
|
|
and t3, PSR_MODE_MASK, t6 // isolate previous mode
|
|
bne t6, 30f // if ne, 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 service routines. Otherwise, increment
|
|
// the time spent in kernel mode for the current thread.
|
|
//
|
|
|
|
srl t3, PSR_IRQL, t6 // t6 = previous Irql
|
|
ldl v0, PbDpcRoutineActive(t5) // v0 = DPC active flag
|
|
subl t6, DISPATCH_LEVEL, t6 // previous Irql - DPC level
|
|
blt t6, 20f // if lt then charge against thread
|
|
|
|
lda t8, PbInterruptTime(t5) // compute interrupt time address
|
|
bgt t6, 10f // if gt, increment interrupt time
|
|
lda t8, PbDpcTime(t5) // compute DPC time address
|
|
beq v0, 20f // if eq, not executing DPC
|
|
|
|
//
|
|
// Update the time spent executing DPC or interrupt level
|
|
//
|
|
// t8 = address of time to increment
|
|
//
|
|
|
|
10:
|
|
ldl t11, 0(t8) // get processor time
|
|
addl t11, 1, t11 // increment processor time
|
|
stl t11, 0(t8) // update processor time
|
|
lda t6, PbKernelTime(t5) // compute address of kernel time
|
|
br zero, 45f // update kernel time
|
|
|
|
//
|
|
// Update the time spent in kernel mode for the current thread and the current
|
|
// thread's process.
|
|
//
|
|
|
|
20:
|
|
ldl t11, ThKernelTime(t0) // get kernel time
|
|
addl t11, 1, t11 // increment kernel time
|
|
stl t11, ThKernelTime(t0) // store updated kernel time
|
|
lda t2, PrKernelTime(t2) // compute process kernel time address
|
|
lda t6, PbKernelTime(t5) // compute processor kernel time addr
|
|
br zero, 40f // join comon code
|
|
|
|
//
|
|
// Update the time spend in user mode for the current thread and the current
|
|
// thread's process.
|
|
//
|
|
|
|
30:
|
|
ldl t11, ThUserTime(t0) // get user time
|
|
addl t11, 1, t11 // increment user time
|
|
stl t11, ThUserTime(t0) // store updated user time
|
|
lda t2, PrUserTime(t2) // compute process user time address
|
|
lda t6, PbUserTime(t5) // compute processor user time address
|
|
|
|
//
|
|
// Update the time spent in kernel/user mode for the current thread's process
|
|
//
|
|
|
|
40:
|
|
#if !defined(NT_UP)
|
|
|
|
ldl_l t11, 0(t2) // get process time
|
|
addl t11, 1, t11 // increment process time
|
|
stl_c t11, 0(t2) // store updated process time
|
|
beq t11, 41f // if eq, store conditional failed
|
|
mb // synchronize subsequent reads
|
|
|
|
#else
|
|
ldl t11,0(t2) // get process time
|
|
addl t11, 1, t11 // increment process time
|
|
stl t11,0(t2) // store updated process time
|
|
#endif
|
|
|
|
//
|
|
// A DPC is not active. If there are DPCs in the DPC queue and a DPC
|
|
// interrupt has not been requested, request a dispatch interrupt in
|
|
// order to initiate the batch processing of the pending DPCs in the
|
|
// DPC queue.
|
|
//
|
|
// N.B. Since an interrupt must be active, the software interrupt request
|
|
// bit in the PRCB can be set to request a dispatch interrupt directly from
|
|
// the interrupt exception handler.
|
|
//
|
|
// Pushing DPCs from the clock interrupt indicates that the current maximum
|
|
// DPC queue depth is too high. If the DPC rate does not exceed the ideal
|
|
// rate, decrement the maximum DPC queue depth and
|
|
// reset the threshold to its original value.
|
|
//
|
|
ldl t1, PbDpcQueueDepth(t5) // get current queue depth
|
|
beq t1, 45f // skip if queue is empty
|
|
ldl t2, PbDpcInterruptRequested(t5) // get dpc interrupt request flag
|
|
bne t2, 45f // skip if flag is set
|
|
ldil a0, DISPATCH_INTERRUPT // a0 = request software interrupt
|
|
stl a0, PbSoftwareInterrupts(t5)
|
|
ldl t3, PbMaximumDpcQueueDepth(t5) // get current DPC queue depth
|
|
subl t3, 1, t4 // decrement
|
|
ldl t2, PbDpcRequestRate(t5) // get old DPC request rate
|
|
ldl t1, KiIdealDpcRate // get ideal DPC rate
|
|
cmpult t2, t1, t2 // compare current with ideal
|
|
ldl t1, KiAdjustDpcThreshold // get system threshold default
|
|
stl t1, PbAdjustDpcThreshold(t5) // reset processor threshold default
|
|
beq t4, 50f // if queue depth==0, skip decrement
|
|
beq t2, 50f // if rate not lt ideal rate, skip decrement
|
|
stl t4, PbMaximumDpcQueueDepth(t5) // set current DPC queue depth
|
|
br zero, 50f // rejoin common code
|
|
|
|
45:
|
|
//
|
|
// There is no need to push a DPC from the clock interrupt. This indicates that
|
|
// the current maximum DPC queue depth may be too low. Decrement the threshold
|
|
// indicator, and if the new threshold is zero, and the current maximum queue
|
|
// depth is less than the maximum, increment the maximum DPC queue
|
|
// depth.
|
|
//
|
|
ldl t1, PbAdjustDpcThreshold(t5) // get current threshold
|
|
subl t1, 1, t2 // decrement threshold
|
|
stl t2, PbAdjustDpcThreshold(t5) // update current threshold
|
|
bne t2, 50f // if threshold nez, skip
|
|
|
|
ldl t1, KiAdjustDpcThreshold // get system threshold default
|
|
stl t1, PbAdjustDpcThreshold(t5) // reset processor threshold default
|
|
|
|
ldl t3, PbMaximumDpcQueueDepth(t5) // get current DPC queue depth
|
|
ldl t1, KiMaximumDpcQueueDepth // get maximum DPC queue depth
|
|
cmpult t3, t1, t2 // compare
|
|
beq t2, 50f // if current not lt maximum, skip
|
|
addl t3, 1, t4 // increment queue depth
|
|
stl t4, PbMaximumDpcQueueDepth(t5) // update current DPC queue depth
|
|
|
|
50:
|
|
//
|
|
// Update the time spent in kernel/user mode for the current processor.
|
|
//
|
|
// t5 = pointer to processor time to increment
|
|
//
|
|
|
|
ldl t11, 0(t6) // get processor time
|
|
addl t11, 1, t11 // increment processor time
|
|
stl t11, 0(t6) // store updated processor time
|
|
|
|
//
|
|
// If the current thread is not the idle thread, decrement its
|
|
// quantum and check to determine if a quantum end has occurred.
|
|
//
|
|
ldl t6, PbIdleThread(t5)
|
|
cmpeq t6, t0, t7
|
|
bne t7, 70f // if nez, current thread is idle thread
|
|
|
|
LoadByte(t7, ThQuantum(t0)) // get current thread quantum
|
|
sll t7, 56, t9
|
|
sra t9, 56, t7
|
|
subl t7, CLOCK_QUANTUM_DECREMENT, t7 // decrement quantum
|
|
StoreByte( t7, ThQuantum(t0) ) // store thread quantum
|
|
bgt t7, 60f // if gtz, quantum remaining
|
|
|
|
//
|
|
// Put processor specific quantum end DPC in the system DPC list and initiate
|
|
// a dispatch interrupt on the current processor.
|
|
//
|
|
// N.B. Since an interrupt must be active, simply set the software interrupt
|
|
// request bit in the PRCB to request a dispatch interrupt directly from
|
|
// the interrupt exception handler.
|
|
//
|
|
|
|
stl sp, PbQuantumEnd(t5) // set quantum end indicator
|
|
|
|
ldil a0, DISPATCH_INTERRUPT // a0 = request sfw interrupt
|
|
stl a0, PbSoftwareInterrupts(t5) // request a sfw interrupt
|
|
|
|
60:
|
|
ret zero, (ra) // return
|
|
|
|
70:
|
|
bis zero, zero, t7
|
|
ret zero, (ra) // return
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
41: br zero, 40b // retry spin lock
|
|
|
|
#endif
|
|
|
|
.end 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.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// TrapFrame (a0) - Supplies a pointer to a trap frame.
|
|
//
|
|
// ProfileSource (a1) - 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
|
|
PfS0: .space 8 // saved integer register s0
|
|
PfRa: .space 8 // return address
|
|
.space 2 * 8 // profile frame length
|
|
ProfileFrameLength:
|
|
|
|
NESTED_ENTRY(KeProfileInterrupt, ProfileFrameLength, zero)
|
|
|
|
bis zero, zero, a1 // set profile source to ProfileTime
|
|
|
|
ALTERNATE_ENTRY(KeProfileInterruptWithSource)
|
|
|
|
lda sp, -ProfileFrameLength(sp) // allocate stack frame
|
|
stq ra, PfRa(sp) // save return address
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
stq s0, PfS0(sp) // save integer register s0
|
|
|
|
#endif
|
|
|
|
PROLOGUE_END
|
|
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
lda s0, KiProfileLock // get address of profile lock
|
|
10: ldl_l t0, 0(s0) // get current lock value
|
|
bis s0, zero, t1 // set ownership value
|
|
bne t0, 15f // if ne, spin lock owned
|
|
stl_c t1, 0(s0) // set spin lock owned
|
|
beq t1, 15f // if eq, store conditional failed
|
|
mb // synchronize subsequent reads after
|
|
// the spinlock is acquired
|
|
|
|
#endif
|
|
|
|
GET_CURRENT_THREAD // v0 = current thread address
|
|
ldl a2, ThApcState + AsProcess(v0) // get address of current process
|
|
addl a2, PrProfileListHead, a2 // compute profile listhead addr
|
|
bsr ra, KiProcessProfileList // process profile list
|
|
|
|
lda a2, KiProfileListHead // get profile listhead address
|
|
bsr ra, KiProcessProfileList // process profile list
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
mb // insure all previous writes go
|
|
// before the lock is released
|
|
stl zero, 0(s0) // set spin lock not owned
|
|
ldq s0, PfS0(sp) // restore s0
|
|
|
|
#endif
|
|
|
|
ldq ra, PfRa(sp) // restore return address
|
|
lda sp, ProfileFrameLength(sp) // deallocate stack frame
|
|
|
|
ret zero, (ra) // return
|
|
|
|
#if !defined(NT_UP)
|
|
|
|
15: ldl t0, 0(s0) // get current lock value
|
|
beq t0, 10b // lock available. retry spinlock
|
|
br zero, 15b // spin in cache until lock ready
|
|
|
|
#endif
|
|
|
|
|
|
.end 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 (a0) - Supplies a pointer to a trap frame.
|
|
//
|
|
// Source (a1) - Supplies profile source to match
|
|
//
|
|
// ListHead (a2) - Supplies a pointer to a profile list.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(KiProcessProfileList)
|
|
|
|
ldl a3, LsFlink(a2) // get address of next entry
|
|
cmpeq a2, a3, t0 // end of list ?
|
|
bne t0, 30f // if ne[true], end of list
|
|
ldl t0, TrFir(a0) // get interrupt PC address
|
|
|
|
GET_PROCESSOR_CONTROL_REGION_BASE // get pcr base
|
|
ldl t6, PcSetMember(v0) // get processor member
|
|
|
|
//
|
|
// Scan profile list and increment profile buckets as appropriate.
|
|
//
|
|
|
|
10: ldl t1, PfRangeBase - PfProfileListEntry(a3) // get base of range
|
|
ldl t2, PfRangeLimit - PfProfileListEntry(a3) // get limit of range
|
|
ldl t4, PfSource - PfProfileListEntry(a3) // get source
|
|
ldl t7, PfAffinity - PfProfileListEntry(a3) // get affinity
|
|
zapnot t4, 3, t4 // source is a SHORT
|
|
cmpeq t4, a1, t5 // check against profile source
|
|
and t7, t6, v0 // check against processor
|
|
beq t5, 20f // if ne, profile source doesn't match
|
|
beq v0, 20f // if ne, processor doesn't match
|
|
cmpult t0, t1, v0 // check against range base
|
|
cmpult t0, t2, t3 // check against range limit
|
|
bne v0, 20f // if ne, less than range base
|
|
beq t3, 20f // if eq, not less than range limit
|
|
subl t0, t1, t1 // compute offset in range
|
|
ldl t2, PfBucketShift - PfProfileListEntry(a3) // get shift count
|
|
ldl v0, PfBuffer - PfProfileListEntry(a3) // prof buffer addr
|
|
zap t1, 0xf0, t1 // force bucket offset to 32bit unit
|
|
srl t1, t2, t3 // compute bucket offset
|
|
bic t3, 0x3, t3 // clear low order offset bits
|
|
addl v0, t3, t3 // compute bucket address
|
|
ldl v0, 0(t3) // increment profile bucket
|
|
addl v0, 1, v0 //
|
|
stl v0, 0(t3) //
|
|
20: ldl a3, LsFlink(a3) // get address of next entry
|
|
cmpeq a2, a3, t1 // end of list?
|
|
beq t1, 10b // if eq[false], more entries
|
|
|
|
30: ret zero, (ra) // return
|
|
|
|
.end KiProcessProfileList
|