|
|
title "Interval Clock Interrupt" ;++ ; ; Copyright (c) 1989 Microsoft Corporation ; ; Module Name: ; ; clockint.asm ; ; Abstract: ; ; This module implements the code necessary to field and process the ; interval clock interrupt. ; ; Author: ; ; Shie-Lin Tzong (shielint) 12-Jan-1990 ; ; Environment: ; ; Kernel mode only. ; ; Revision History: ; ; bryanwi 20-Sep-90 ; ; Add KiSetProfileInterval, KiStartProfileInterrupt, ; KiStopProfileInterrupt procedures. ; KiProfileInterrupt ISR. ; KiProfileList, KiProfileLock are declared here. ; ; shielint 10-Dec-90 ; Add performance counter support. ; Move system clock to irq8, ie we now use RTC to generate system ; clock. Performance count and Profile use timer 1 counter 0. ; The interval of the irq0 interrupt can be changed by ; KiSetProfileInterval. Performance counter does not care about the ; interval of the interrupt as long as it knows the rollover count. ; Note: Currently I implemented 1 performance counter for the whole ; i386 NT. It works on UP and SystemPro. ; ;--
.386p .xlist KERNELONLY equ 1 include ks386.inc include callconv.inc ; calling convention macros include i386\kimacro.inc include mac386.inc .list
EXTRNP Kei386EoiHelper EXTRNP HalRequestSoftwareInterrupt,1,IMPORT,FASTCALL EXTRNP _HalEndSystemInterrupt,2,IMPORT extrn _KeTimeIncrement:DWORD extrn _KeMaximumIncrement:DWORD extrn _KeTickCount:DWORD extrn _KeTimeAdjustment:DWORD extrn _KiAdjustDpcThreshold:DWORD extrn _KiIdealDpcRate:DWORD extrn _KiMaximumDpcQueueDepth:DWORD extrn _KiTickOffset:DWORD extrn _KiTimerTableListHead:DWORD extrn _KiProfileListHead:DWORD extrn _KiProfileLock:DWORD extrn _KiProfileInterval:DWORD extrn _KdDebuggerEnabled:BYTE EXTRNP _DbgBreakPoint EXTRNP _DbgBreakPointWithStatus,1 EXTRNP _KdPollBreakIn EXTRNP _KiDeliverApc,3 extrn _KeI386MachineType:DWORD extrn _PPerfGlobalGroupMask:DWORD EXTRNP PerfProfileInterrupt,2,,FASTCALL
if DBG extrn _DbgPrint:near extrn _KiDPCTimeout:DWORD extrn _MsgDpcTimeout:BYTE endif
ifdef NT_UP LOCK_INC equ inc else LOCK_INC equ lock inc endif
_DATA SEGMENT DWORD PUBLIC 'DATA' public ProfileCount ProfileCount DD 0
_DATA ends
page ,132 subttl "Update System Time"
_TEXT$00 SEGMENT DWORD PUBLIC 'CODE' ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING ;++ ; ; VOID ; KeUpdateSystemTime ( ; IN KIRQL PreviousIrql, ; IN KTRAP_FRAME TrapFrame ; ) ; ; Routine Description: ; ; This routine is entered as the result of an interrupt generated by CLOCK2. ; 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 multiprocessor ; system. The remainder of the processors only execute the quantum end ; and runtime update code. ; ; N.B. This routine is not called, but directly jumped to. Thus, there ; is no return address. It returns via the INTERRUPT_EXIT macro. ; ; Arguments: ; ; PreviousIrql (esp) - supplies previous irql of system ; ; HardwareVector (esp+4) - supplies hardware vector for EndSystemInterrupt ; ; TrapFrame (esp+8) - supplies base of trap frame ; ; EAX is the TimeIncrement value ; ; EBP is a pointer to the trap frame ; ; ; Environment: ; ; IRQL = CLOCK_LEVEL ; ; Return Value: ; ; None. ; ;-- cPublicProc _KeUpdateSystemTime ,0
.FPO (2, 0, 0, 0, 0, 1) ; treat params as locals since functions is JMPed too
if DBG cmp byte ptr PCR[PcPrcbData+PbSkipTick], 0 jnz kust_skiptick endif
; ; Update 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 to read time. ;
mov ecx,USER_SHARED_DATA ; get address of user shared data mov edi,[ecx].UsInterruptTime+0 ; get low interrupt time mov esi,[ecx].UsInterruptTime+4 ; get high interrupt time add edi,eax ; add time increment adc esi,0 ; propagate carry mov [ecx].UsInterruptTime+8,esi ; store high 2 interrupt time mov [ecx].UsInterruptTime+0,edi ; store low interrupt time mov [ecx].UsInterruptTime+4,esi ; store high 1 interrupt time
sub _KiTickOffset,eax ; subtract time increment mov eax,_KeTickCount+0 ; get low tick count mov ebx,eax ; copy low tick count jg kust10 ; if greater, not complete tick
; ; 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 to read time. ;
mov ebx,USER_SHARED_DATA ; get address of user shared data mov ecx,[ebx].UsSystemTime+0 ; get low system time mov edx,[ebx].UsSystemTime+4 ; get high system time add ecx,_KeTimeAdjustment ; add time increment adc edx,0 ; propagate carry mov [ebx].UsSystemTime+8,edx ; store high 2 system time mov [ebx].UsSystemTime+0,ecx ; store low system time mov [ebx].UsSystemTime+4,edx ; store high 1 system time mov ebx,eax ; restore low tick count
; ; Update 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 to read count. ;
mov ecx,eax ; copy low tick count mov edx,_KeTickCount+4 ; get high tick count add ecx,1 ; increment tick count adc edx,0 ; propagate carry mov _KeTickCount+8,edx ; store high 2 tick count mov _KeTickCount+0,ecx ; store low tick count mov _KeTickCount+4,edx ; store high 1 tick count mov USERDATA[UsTickCount]+8, edx ; store USD high 2 tick count mov USERDATA[UsTickCount]+0, ecx ; store USD low tick count mov USERDATA[UsTickCount]+4, edx ; store USD high 1 tick count
if 0 ; debug code push eax mov edx, esi mov eax, edi ; (eax:edx) = InterruptTime mov ecx, _KeMaximumIncrement div ecx cmp al, bl ; same bucket? je short @f int 3 ; no - stop @@: pop eax endif
; ; Check to determine if a timer has expired. ; (edi:esi) = KiInterruptTime ; (eax) = KeTickCount.LowPart ; (ebx) = KeTickCount.LowPart ;
and eax,TIMER_TABLE_SIZE-1 ; isolate current hand value lea ecx,_KiTimerTableListHead[eax*8] ; get listhead addrees mov edx,[ecx] ; get first entry address cmp ecx,edx ; check if list is empry je short kust5 ; if equal, list is empty cmp esi,[edx].TiDueTime.TmHighTime-TiTimerListEntry ; compare high jb short kust5 ; if below, timer has not expired ja short kust15 ; if above, timer has expired cmp edi,[edx].TiDueTime.TmLowTime-TiTimerListEntry ; compare low jae short kust15 ; if above or equal, time has expired kust5: inc eax ; advance hand value to next entry inc ebx
; ; Check to determine if a timer has expired. ; (edi:esi) = KiInterruptTime ; (eax) = bucket ; (ebx) = KeTickCount.LowPart ;
kust10: and eax,TIMER_TABLE_SIZE-1 ; isolate current hand value lea ecx,_KiTimerTableListHead[eax*8] ; get listhead addrees mov edx,[ecx] ; get first entry address cmp ecx,edx ; check if list is empry je kustxx ; if equal, list is empty cmp esi,[edx].TiDueTime.TmHighTime-TiTimerListEntry ; compare high jb kustxx ; if below, timer has not expired ja short kust15 ; if above, timer has expired cmp edi,[edx].TiDueTime.TmLowTime-TiTimerListEntry ; compare low jb kustxx ; if below, timer has not expired
kust15: ; ; Timer has expired, put timer expiration DPC in the current processor's DPC ; queue. ; ; (ebx) = KeTickCount.LowPart ;
mov ecx,PCR[PcPrcb] ; get processor control block address cmp dword ptr [ecx]+PbTimerRequest, 0 ; check if expiration active jne short kustxx ; if ne, expiration already active mov [ecx]+PbTimerRequest, esp ; set timer request mov [ecx]+PbTimerHand, ebx ; set timer hand value mov ecx, DISPATCH_LEVEL ; request dispatch interrupt fstCall HalRequestSoftwareInterrupt ;
; ; If the debugger is enabled, check if a break is requested. ;
kustxx: cmp _KdDebuggerEnabled, 0 ; check if a debugger is enabled jnz short kust45 ;if nz, debugger is enabled
kust30: cmp _KiTickOffset,0 ; check if full tick jg short Kust40 ; if not less, not a full tick
mov eax,_KeMaximumIncrement ; get maximum time incrmeent add _KiTickOffset,eax ; add maximum tine to residue
; ; call KeUpdateRunTime to do the actual work ;
; TOS const PreviousIrql push [esp] call _KeUpdateRunTime@4
; ; Do interrupt exit processing ;
INTERRUPT_EXIT
kust40: inc dword ptr PCR[PcPrcbData+PbInterruptCount] INTERRUPT_EXIT
kust45: stdCall _KdPollBreakIn or al,al jz short kust30 stdCall _DbgBreakPointWithStatus,<DBG_STATUS_CONTROL_C> jmp short kust30
if DBG
kust_skiptick: mov byte ptr PCR[PcPrcbData+PbSkipTick], 0 jmp short kust40
endif
stdENDP _KeUpdateSystemTime
page ,132 subttl "Update Thread and Process Runtime" ;++ ; ; Routine Description: ; ; This routines does the actual work to update the runtime of the current ; thread, update the runtime of the current thread's process, and ; decrement the current thread's quantum. ; ; It also updates the system global counters for user and kernel mode time. ; ; It increments InterruptCount so that clock ticks get counted as ; interrupts. ; ; Arguments: ; ; esp+4 constant PreviousIrql ; ; ebp MUST point to the machine state frame. ; ; Return Value: ; ; None. ; ;--
cPublicProc _KeUpdateRunTime ,1 cPublicFpo 1, 1
mov eax, PCR[PcSelfPcr] if DBG cmp byte ptr [eax]+PcPrcbData+PbSkipTick, 0 jnz kutp_skiptick endif push ebx ; we will destroy ebx inc dword ptr [eax]+PcPrcbData+PbInterruptCount mov ebx, [eax]+PcPrcbData+PbCurrentThread ; (ebx)->current thread mov ecx, ThApcState+AsProcess[ebx] ; (ecx)->current thread's process
test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK jne Kutp20 ; if ne, user mode
test byte ptr [ebp]+TsSegCs, MODE_MASK ; test if prev mode was kernel jne Kutp20 ; if ne, user mode
; ; Update the total time spent in kernel mode ;
inc dword ptr [eax].PcPrcbData.PbKernelTime cmp byte ptr [esp+8], DISPATCH_LEVEL jc short Kutp4 ; OldIrql<2, then kernel ja short Kutp3 ; OldIrql>2, then interrupt
cmp byte ptr PCR[PcPrcbData.PbDpcRoutineActive], 0 jz short Kutp4 ; Executing Dpc?, no then thread time
inc dword ptr [eax].PcPrcbData.PbDpcTime if DBG ; ; Check for dpcs which run for too long ;
inc dword ptr [eax].PcPrcbData.PbDebugDpcTime mov edx, _KiDPCTimeout cmp dword ptr [eax].PcPrcbData.PbDebugDpcTime, edx jc Kutp50 ; Jump if not over limit
; ; Dpc time has exceeded the allowed quanta ;
push offset FLAT:_MsgDpcTimeout ; push message address call _DbgPrint ; print debug message add esp, 1 * 4 ; remove arguments from stack
cmp _KdDebuggerEnabled, 0 ; check if debugger enabled je short Kutp6 ; if eq, no debugger, continue stdCall _DbgBreakPoint ; break into debugger
Kutp6: mov eax, PCR[PcSelfPcr] ; restore PCR address mov dword ptr [eax].PcPrcbData.PbDebugDpcTime, 0 ; Reset Time endif jmp Kutp50
ALIGN 4 Kutp3: ; ; Update the time spent at interrupt time for this processor ;
inc dword ptr [eax].PcPrcbData.PbInterruptTime jmp Kutp50
ALIGN 4 Kutp4:
; ; Update the time spent in kernel mode for the current thread and the current ; thread's process. ; inc dword ptr [ebx]+ThKernelTime
LOCK_INC dword ptr [ecx]+PrKernelTime
jmp Kutp50
; ; Update total time spent in user mode ;
ALIGN 4 Kutp20: inc dword ptr [eax].PcPrcbData.PbUserTime ; ; Update the time spend in user mode for the current thread and the current ; thread's process. ;
inc dword ptr [ebx]+ThUserTime
LOCK_INC dword ptr [ecx]+PrUserTime
; ; Update the DPC request rate which is computed as the average between ; the previous rate and the current rate. ;
ALIGN 4 Kutp50: mov ecx, [eax].PcPrcbData.PbDpcCount ; get current DPC count mov edx, [eax].PcPrcbData.PbDpcLastCount ; get last DPC count mov [eax].PcPrcbData.PbDpcLastCount, ecx ; set last DPC count sub ecx, edx ; compute count during interval add ecx, [eax].PcPrcbData.PbDpcRequestRate ; compute sum shr ecx, 1 ; average current and last mov [eax].PcPrcbData.PbDpcRequestRate, ecx ; set new DPC request rate
; ; 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. ;
cmp dword ptr [eax].PcPrcbData.PbDpcQueueDepth, 0 ; check queue depth je short Kutp53 ; if eq, DPC queue depth is zero cmp byte ptr [eax].PcPrcbData.PbDpcRoutineActive, 0 ; check if DPC active jne short Kutp53 ; if ne, DPC routine active cmp byte ptr [eax].PcPrcbData.PbDpcInterruptRequested, 0 ; check if interrupt jne short Kutp53 ; if ne, DPC routine active mov ecx, DISPATCH_LEVEL ; request a dispatch interrupt fstCall HalRequestSoftwareInterrupt ; mov eax, PCR[PcSelfPcr] ; restore address of current PCR mov ecx, [eax].PcPrcbData.PbDpcRequestRate ; get DPC request rate mov edx, _KiAdjustDpcThreshold ; reset initial threshold counter mov [eax].PcPrcbData.PbAdjustDpcThreshold, edx ; cmp ecx, _KiIdealDpcRate ; test if current rate less than ideal jge short Kutp55 ; if ge, rate greater or equal ideal cmp [eax].PcPrcbData.PbMaximumDpcQueueDepth, 1 ; check if depth one je short Kutp55 ; if eq, maximum depth is one dec dword ptr [eax].PcPrcbData.PbMaximumDpcQueueDepth ; decrement depth jmp short Kutp55 ;
; ; 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. ;
Kutp53: dec dword ptr [eax].PcPrcbData.PbAdjustDpcThreshold ; decrement threshold jnz short Kutp55 ; if nz, threshold not zero mov ecx, _KiAdjustDpcThreshold ; reset initial threshold counter mov [eax].PcprcbData.PbAdjustDpcThreshold, ecx ; mov ecx, _KiMaximumDpcQueueDepth ; get maximum DPC queue depth cmp ecx, [eax].PcPrcbData.PbMaximumDpcQueueDepth ; check depth je short Kutp55 ; if eq, aleady a maximum level inc dword ptr [eax].PcPrcbData.PbMaximumDpcQueueDepth ; increment maximum depth
; ; Decrement current thread quantum and check to determine if a quantum end ; has occurred. ;
ALIGN 4 Kutp55: sub byte ptr [ebx]+ThQuantum, CLOCK_QUANTUM_DECREMENT ; decrement quantum jg Kutp75 ; if > 0, time remaining on quantum
; ; Set quantum end flag and initiate a dispather interrupt on the current ; processor. ;
cmp ebx,[eax].PcPrcbData.PbIdleThread ; check if idle thread jz Kutp75 ; if z, then idle thread mov byte ptr [eax].PcPrcbData.PbQuantumEnd, 1 ; set quantum end indicator mov ecx, DISPATCH_LEVEL ; request dispatch interrupt fstCall HalRequestSoftwareInterrupt ; Kutp75: ; pop ebx ; stdRET _KeUpdateRunTime ;
if DBG kutp_skiptick: mov byte ptr [eax]+PcPrcbData+PbSkipTick, 0 stdRET _KeUpdateRunTime endif
stdENDP _KeUpdateRunTime
;++ ; ; PROFILING SUPPORT ; ;--
;++ ; ; VOID ; KeProfileInterrupt ( ; IN PKTRAP_FRAME TrapFrame, ; ) ; ; Routine Description: ; ; This procedure is the ISR for the profile sampling interrupt, ; which for x86 machines is driven off the 8254 timer1 channel 0. ; ; The procedure scans the list of profile objects, looking for those ; which match the address space and return program counter captured ; at entry. For each object that does match, the counter in its ; profile buffer matching the bucket the PC falls into is computed, ; and that counter is incremented. ; ; N.B. This routine is executed on all processors in a multiprocess ; system. ; ; Arguments: ; ; Return Address (esp) ; ; TrapFrame (esp+4) - supplies pointer to profile trap frame ; ; Environment: ; ; IRQL = KiProfileIrql ; ; ; Return Value: ; ; None. ; ; WARNING: Uses ALL registers ; ;--
cPublicProc _KeProfileInterrupt ,1 ; ; rearrange arguments to pass a source of 0 to KeProfileInterruptWithSource ; pop eax ; return code in eax pop ebx ; trap frame in ebx push 0 ; push source of 0 (ProfileTime) push ebx ; push trap frame push eax ; push return address jmp short _KeProfileInterruptWithSource@8 stdENDP _KeProfileInterrupt
;++ ; ; VOID ; KeProfileInterruptWithSource ( ; IN PKTRAP_FRAME TrapFrame, ; IN KPROFILE_SOURCE ProfileSource ; ) ; ; Routine Description: ; ; This procedure is the ISR for the multiple-source profile interrupt. ; ; Since no x86 HAL currently implements any source other than the ; clock interrupt, this routine is just a stub that calls KeProfileInterrupt ; ; Arguments: ; ; Return Address (esp) ; ; TrapFrame (esp+4) - supplies pointer to profile trap frame ; ; ProfileSource (esp+8) - supplies source of profile interrupt ; ; Environment: ; ; IRQL = KiProfileIrql ; ; ; Return Value: ; ; None. ; ; WARNING: Uses ALL registers ; ;-- cPublicProc _KeProfileInterruptWithSource,2
kipieip equ <dword ptr [ebp+TsEip]> kipsegcs equ <word ptr [ebp+TsSegCs]> kipeflags equ <dword ptr [ebp+TsEFlags]>
mov ebp, dword ptr [esp+4] ; (ebp)-> trap frame inc dword ptr PCR[PcPrcbData+PbInterruptCount]
cmp _PPerfGlobalGroupMask, 0 ; check if event tracing is on je short kipi03
;; add profile interrupt to perfinfo mov ecx, [esp+8] mov edx,kipieip fstCall PerfProfileInterrupt mov ebp, dword ptr [esp+4] ; (ebp)-> trap frame kipi03:
ifndef NT_UP lea eax,_KiProfileLock kipi05: ACQUIRE_SPINLOCK eax,kipi96 endif
; ; Update profile data ; ; NOTE: ; System and Process update loops are duplicates, to avoid overhead ; of call instruction in what could be very high freq. interrupt. ; be sure to update both loops for changes. ; ; NOTE: ; The process loop contains code to update segment profile objects. ; This code is not present in the system loop, because we do not ; allow attachment of profile objects for non-flat segments on a ; system wide basis. ; ; NOTE: ; Profiling in V86 mode is handled by converting the CS:IP value to ; a linear address (CS<<4 + IP) ;
inc ProfileCount ; total number of hits
; ; Update system profile entries ;
mov ebx, kipieip mov edx,offset FLAT:_KiProfileListHead mov esi,[edx].LsFlink ; (esi) -> profile object ifndef NT_UP mov edi, PCR[PcSetMember] ; (edi) = current processor endif mov ecx, [esp+8] ; (cx) = profile source cmp esi,edx je kipi30 ; end of system list, go do process
; ; (ebx) = sample program counter ; (esi) -> profile object ;
ALIGN 4 kipi10: cmp ebx,[esi+PfRangeBase-PfProfileListEntry] ; >= base? jb kipi20 ; no, skip entry cmp ebx,[esi+PfRangeLimit-PfProfileListEntry] ; < limit? jae kipi20 ; no, skip entry cmp cx,word ptr [esi+PfSource-PfProfileListEntry] ; == source? jne kipi20 ; no, skip entry ifndef NT_UP test edi,[esi+PfAffinity-PfProfileListEntry] ; affinity match? jz kipi20 ; no, skip entry endif
; ; RangeBase <= program counter < RangeLimit, we have a hit ;
sub ebx,[esi+PfRangeBase-PfProfileListEntry] ; (ebx) = offset in profile range mov cl,[esi+PfBucketShift-PfProfileListEntry] shr ebx,cl and ebx,NOT 3 ; (ebx) = offset of counter for bucket mov edi,[esi+PfBuffer-PfProfileListEntry] ; (edi) -> buffer inc dword ptr [edi+ebx] ; record hit mov ebx, kipieip ; (ebx) = sample pc mov ecx, [esp+8] ; (cx) = profile source ifndef NT_UP mov edi, PCR[PcSetMember] ; (edi) = current processor endif
; ; Go to next entry ;
ALIGN 4 kipi20: mov esi,[esi].LsFlink ; (esi) -> profile object cmp esi,edx jne kipi10 ; not end of list, repeat
; ; Update process profile entries ; (ebx) = sample program counter ;
ALIGN 4 kipi30: mov eax,PCR[PcPrcbData+PbCurrentThread] ; (eax)-> current thread mov eax,ThApcState+AsProcess[eax] ; (eax)-> current process lea edx,[eax]+PrProfileListHead ; (edx)-> listhead mov esi,[edx].LsFlink ; (esi)-> profile object cmp esi,edx je kipi60 ; process list end, return
; ; Check for 16 bitness ; movzx ecx,word ptr kipsegcs test kipeflags,EFLAGS_V86_MASK jnz kipi100 ; convert cs:ip to linear
cmp cx,KGDT_R0_CODE je short kipi40
cmp cx,KGDT_R3_CODE or RPL_MASK jne kipi110
; ; (ebx) = sample program counter ; (esi) -> profile object ;
ALIGN 4 kipi40: cmp [esi+PfSegment-PfProfileListEntry],word ptr 0 ; flat object? jne kipi50 ; no, skip entry cmp ebx,[esi+PfRangeBase-PfProfileListEntry] ; >= base? jb kipi50 ; no, skip entry cmp ebx,[esi+PfRangeLimit-PfProfileListEntry] ; < limit? jae kipi50 ; no, skip entry mov ecx, [esp+8] ; (cx) = profile source cmp cx,word ptr [esi+PfSource-PfProfileListEntry] ; == source? jne kipi50 ; no, skip entry ifndef NT_UP mov edi,PCR[PcSetMember] ; (edi) = set member test edi,[esi+PfAffinity-PfProfileListEntry] ; affinity match? jz kipi50 ; no, skip entry endif
; ; RangeBase <= program counter < RangeLimit, we have a hit ;
sub ebx,[esi+PfRangeBase-PfProfileListEntry] ; (ebx) = offset in profile range mov cl,[esi+PfBucketShift-PfProfileListEntry] shr ebx,cl and ebx,NOT 3 ; (ebx) = offset of counter for bucket mov edi,[esi+PfBuffer-PfProfileListEntry] ; (edi) -> buffer inc dword ptr [edi+ebx] ; record hit mov ebx, kipieip ; (ebx) = sample pc mov ecx, [esp+8] ; (cx) = profile source
; ; Go to next entry ;
ALIGN 4 kipi50: mov esi,[esi].LsFlink ; (esi) -> profile object cmp esi,edx jne kipi40 ; not end of list, repeat
ALIGN 4 kipi60:
ifndef NT_UP lea eax,_KiProfileLock RELEASE_SPINLOCK eax endif stdRet _KeProfileInterruptWithSource
ifndef NT_UP ALIGN 4 kipi96: SPIN_ON_SPINLOCK eax,kipi05,,DbgMp endif
ALIGN 4 kipi100: shl ecx,4 ; segment -> paragraph add ebx,ecx ; paragraph offset -> linear jmp kipi40
; ; Update segment profile objects ;
; ; (ebx) = sample program counter ; (esi) -> profile object ;
ALIGN 4 kipi110: cmp [esi+PfSegment-PfProfileListEntry],ecx ; This segment? jne kipi120 ; no, skip entry cmp ebx,[esi+PfRangeBase-PfProfileListEntry] ; >= base? jb kipi120 ; no, skip entry cmp ebx,[esi+PfRangeLimit-PfProfileListEntry] ; < limit? jae kipi120 ; no, skip entry mov ecx, [esp+8] ; (cx) = profile source cmp cx,word ptr [esi+PfSource-PfProfileListEntry] ; == source? jne kipi120 ; no, skip entry ifndef NT_UP mov edi,PCR[PcSetMember] ; (edi) = set member test edi,[esi+PfAffinity-PfProfileListEntry] ; affinity match? jnz kipi120 ; no, skip entry endif
; ; RangeBase <= program counter < RangeLimit, we have a hit ;
sub ebx,[esi+PfRangeBase-PfProfileListEntry] ; (ebx) = offset in profile range mov cl,[esi+PfBucketShift-PfProfileListEntry] shr ebx,cl and ebx,NOT 3 ; (ebx) = offset of counter for bucket mov edi,[esi+PfBuffer-PfProfileListEntry] ; (edi) -> buffer inc dword ptr [edi+ebx] ; record hit mov ebx, kipieip ; (ebx) = sample pc mov cx,kipsegcs ; ecx = sample cs
; ; Go to next entry ;
ALIGN 4 kipi120: mov esi,[esi].LsFlink ; (esi) -> profile object cmp esi,edx jne kipi110 ; not end of list, repeat
jmp kipi60
stdENDP _KeProfileInterruptWithSource _TEXT$00 ends end
|