KiIdleLoop线程分析之优先级为0到调用nt!SwapContext切换到NextThread的一个例子
0: kd> g
Breakpoint 16 hit
eax=00000001 ebx=00000102 ecx=00000002 edx=00000000 esi=f7737120 edi=00000000
eip=804ee4f8 esp=f78aac9c ebp=f78aacc0 iopl=0 nv up ei pl nz na po nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000202
hal!HalRequestSoftwareInterrupt:
804ee4f8 643a0d95000000 cmp cl,byte ptr fs:[95h] fs:0030:00000095=00
1: kd> dx -id 0,0,89831250 -r1 ((basesrv!_KPRCB *)0xffdff120)
((basesrv!_KPRCB *)0xffdff120) : 0xffdff120 [Type: _KPRCB *]
+0x000\] MinorVersion : 0x1 \[Type: unsigned short
+0x002\] MajorVersion : 0x1 \[Type: unsigned short
+0x004\] CurrentThread : 0x895f2a78 \[Type: _KTHREAD \*
+0x008\] NextThread : 0x0 \[Type: _KTHREAD \*
+0x00c\] IdleThread : 0x80b200c0 \[Type: _KTHREAD \*
+0x928\] ReadySummary : 0x0 \[Type: unsigned long
+0x92c\] SelectNextLast : 0x0 \[Type: unsigned long
+0x930\] DispatcherReadyListHead \[Type: _LIST_ENTRY \[32\]
+0xa30\] DeferredReadyListHead \[Type: _SINGLE_LIST_ENTRY
1: kd> dt kthread 8952bc18
CSRSRV!KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x010 MutantListHead : _LIST_ENTRY [ 0x8952bc28 - 0x8952bc28 ]
+0x018 InitialStack : 0xba583000 Void
+0x01c StackLimit : 0xba580000 Void
+0x020 KernelStack : 0xba582c78 Void
+0x024 ThreadLock : 0
+0x028 ContextSwitches : 0x2d7
+0x02c State : 0x3 ''
+0x02d NpxState : 0xa ''
+0x02e WaitIrql : 0 ''
+0x02f WaitMode : 1 ''
+0x030 Teb : 0x7ffd9000 Void
+0x034 ApcState : _KAPC_STATE
+0x04c ApcQueueLock : 0
+0x050 WaitStatus : 0n258
+0x054 WaitBlockList : 0x8952bd00 _KWAIT_BLOCK
+0x058 Alertable : 0 ''
+0x059 WaitNext : 0 ''
+0x05a WaitReason : 0x4 ''
+0x05b Priority : 8 ''
1: kd> dx -id 0,0,89831250 -r1 ((basesrv!_KPRCB *)0xf7737120)
((basesrv!_KPRCB *)0xf7737120) : 0xf7737120 [Type: _KPRCB *]
+0x000\] MinorVersion : 0x1 \[Type: unsigned short
+0x002\] MajorVersion : 0x1 \[Type: unsigned short
+0x004\] CurrentThread : 0xf7739fa0 \[Type: _KTHREAD \*
+0x008\] NextThread : 0x8952bc18 \[Type: _KTHREAD \*
+0x00c\] IdleThread : 0xf7739fa0 \[Type: _KTHREAD \*
+0x928\] ReadySummary : 0x0 \[Type: unsigned long
+0x92c\] SelectNextLast : 0x0 \[Type: unsigned long
+0x930\] DispatcherReadyListHead \[Type: _LIST_ENTRY \[32\]
+0xa30\] DeferredReadyListHead \[Type: _SINGLE_LIST_ENTRY
1: kd> dx -id 0,0,89831250 -r1 ((basesrv!_KTHREAD *)0xf7739fa0)
((basesrv!_KTHREAD *)0xf7739fa0) : 0xf7739fa0 [Type: _KTHREAD *]
+0x000\] Header \[Type: _DISPATCHER_HEADER
+0x010\] MutantListHead \[Type: _LIST_ENTRY
+0x018\] InitialStack : 0xf78ab000 \[Type: void \*
+0x01c\] StackLimit : 0xf78a8000 \[Type: void \*
+0x020\] KernelStack : 0xf78aad4c \[Type: void \*
+0x024\] ThreadLock : 0x0 \[Type: unsigned long
+0x028\] ContextSwitches : 0x2b9a \[Type: unsigned long
+0x02c\] State : 0x2 \[Type: unsigned char
+0x02d\] NpxState : 0xa \[Type: unsigned char
+0x02e\] WaitIrql : 0x2 \[Type: unsigned char
+0x02f\] WaitMode : 0 \[Type: char
+0x030\] Teb : 0x0 \[Type: void \*
+0x034\] ApcState \[Type: _KAPC_STATE
+0x04c\] ApcQueueLock : 0x0 \[Type: unsigned long
+0x050\] WaitStatus : 0 \[Type: long
+0x054\] WaitBlockList : 0x0 \[Type: _KWAIT_BLOCK \*
+0x058\] Alertable : 0x0 \[Type: unsigned char
+0x059\] WaitNext : 0x0 \[Type: unsigned char
+0x05a\] WaitReason : 0x0 \[Type: unsigned char
+0x05b\] Priority : 0 \[Type: char
+0x113\] Quantum : 114 'r' \[Type: char
1: kd> !thread 0xf7739fa0
THREAD f7739fa0 Cid 0000.0000 Teb: 00000000 Win32Thread: 00000000 RUNNING on processor 1
Not impersonating
Owning Process 80b20320 Image: Idle
Attached Process N/A Image: N/A
Wait Start TickCount 0 Ticks: 274655302 (49:16:04:49.093)
Context Switch Count 11162 IdealProcessor: 0
UserTime 00:00:00.000
KernelTime 00:01:46.234
Stack Init f78ab000 Current f78aad4c Base f78ab000 Limit f78a8000 Call 00000000
Priority 0 BasePriority 0 PriorityDecrement 0 IoPriority 0 PagePriority 0
ChildEBP RetAddr Args to Child
f78aac98 80a3ccf7 bae6aa16 f7737dd0 f78aad50 hal!HalRequestSoftwareInterrupt (FPO: [0,0,0]) [d:\srv03rtm\base\hals\halmps\i386\mpswint.asm @ 84]
f78aaca8 804ed906 f78aacc0 00000000 00000402 nt!KiIpiServiceRoutine+0x6f (FPO: [2,3,0]) [d:\srv03rtm\base\ntos\ke\i386\mpipia.asm @ 152]
f78aaca8 bae6aa16 f78aacc0 00000000 00000402 hal!HalpIpiHandler+0xca (FPO: [0,2] TrapFrame @ f78aacc0) [d:\srv03rtm\base\hals\halmps\i386\mpipi.asm @ 718]
f78aad50 80b00a60 00000000 0000000e 00000000 processr!AcpiC1Idle+0x12 (FPO: [0,2,0]) [d:\srv03rtm\base\hals\processor\lib\i386\cstate.asm @ 134]
f78aad54 00000000 0000000e 00000000 00000000 nt!KiIdleLoop+0xc (FPO: [0,0,0]) [d:\srv03rtm\base\ntos\ke\i386\ctxswap.asm @ 1362]
1: kd> kc 2
00 hal!HalRequestSoftwareInterrupt
01 nt!KiIpiServiceRoutine
1: kd> g
Breakpoint 46 hit
WARNING: Process directory table base 7A00C000 doesn't match CR3 00039000
WARNING: Process directory table base 7A00C000 doesn't match CR3 00039000
eax=00000002 ebx=f7737000 ecx=00000001 edx=0000001b esi=8952bc18 edi=f7739fa0
eip=80b007f0 esp=f78aad54 ebp=80b20320 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!SwapContext:
80b007f0 51 push ecx
windbg> .open -a ffffffff804ee4f8
1: kd> kc 2
00 nt!SwapContext
01 nt!KiIdleLoop
windbg> .open -a ffffffff80b00a60
;++
;
; VOID
; KiIdleLoop(
; VOID
; )
;
; Routine Description:
;
; This routine continuously executes the idle loop and never returns.
;
; Arguments:
;
; ebx - Address of the current processor's PCR.
;
; Return value:
;
; None - routine never returns.
;
;--
cPublicFastCall KiIdleLoop ,0
cPublicFpo 0, 0
if DBG
xor edi, edi ; reset poll breakin counter
endif
jmp short kid20 ; Skip HalIdleProcessor on first iteration
;
; There are no entries in the DPC list and a thread has not been selected
; for execution on this processor. Call the HAL so power managment can be
; performed.
;
; N.B. The HAL is called with interrupts disabled. The HAL will return
; with interrupts enabled.
;
; N.B. Use a call instruction instead of a push-jmp, as the call instruction
; executes faster and won't invalidate the processor's call-return stack
; cache.
;
kid10: lea ecx, [ebx].PcPrcbData.PbPowerState
call dword ptr [ecx].PpIdleFunction ; (ecx) = Arg0
;
; Give the debugger an opportunity to gain control on debug systems.
;
; N.B. On an MP system the lowest numbered idle processor is the only
; processor that polls for a breakin request.
;
kid20:
if DBG
ifndef NT_UP
mov eax, _KiIdleSummary ; get idle summary
mov ecx, [ebx].PcSetMember ; get set member
dec ecx ; compute right bit mask
and eax, ecx ; check if any lower bits set
jnz short CheckDpcList ; if nz, not lowest numbered
endif
dec edi ; decrement poll counter
jg short CheckDpcList ; if g, not time to poll
POLL_DEBUGGER ; check if break in requested
endif
kid30:
if DBG
ifndef NT_UP
mov edi, 20 * 1000 ; set breakin poll interval
else
mov edi, 100 ; UP idle loop has a HLT in it
endif
endif
CheckDpcList0: ;
YIELD
;
; Disable interrupts and check if there is any work in the DPC list of the
; current processor or a target processor.
;
CheckDpcList:
;
; N.B. The following code enables interrupts for a few cycles, then
; disables them again for the subsequent DPC and next thread
; checks.
;
sti ; enable interrupts
nop ;
nop ;
cli ; disable interrupts
;
; Process the deferred procedure call list for the current processor.
;
mov eax, [ebx]+PcPrcbData+PbDpcQueueDepth ; get DPC queue depth
or eax, [ebx]+PcPrcbData+PbTimerRequest ; merge timer request
ifndef NT_UP
or eax, [ebx]+PcPrcbData+PbDeferredReadyListHead ; merge deferred list head
endif
jz short CheckNextThread ; if z, no DPC's or timers to process
mov cl, DISPATCH_LEVEL ; set interrupt level
fstCall HalClearSoftwareInterrupt ; clear software interrupt
lea ecx, [ebx].PcPrcbData ; set current PRCB address
CAPSTART <@KiIdleLoop@0,@KiRetireDpcList@4>
fstCall KiRetireDpcList ; process the current DPC list
CAPEND <@KiIdleLoop@0>
if DBG
xor edi, edi ; clear breakin poll interval
endif
;
; Check if a thread has been selected to run on the current processor.
;
CheckNextThread: ;
cmp dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; thread selected?
ifdef NT_UP
je short kid10 ; if eq, no thread selected
else
je kid40 ; if eq, no thread selected.
endif
;
; Raise IRQL to synchronization level and enable interrupts.
;
ifndef NT_UP
RaiseIrql SYNCH_LEVEL, NoOld ; raise IRQL to synchronizaiton level
endif
sti ; enable interrupts
mov edi, [ebx].PcPrcbData.PbCurrentThread ; get idle thread address
;
; Set context swap busy for idle thread and acquire the PRCB lock.
;
ifndef NT_UP
mov byte ptr [edi].ThSwapBusy, 1 ; set context swap busy
lock bts dword ptr [ebx].PcPrcbData.PbPrcbLock, 0 ; try to acquire PRCB Lock
jnc short kid33 ; if nc, PRCB lock acquired
lea ecx, [ebx].PcPrcbData.PbPrcbLock ; get PRCB lock address
fstCall KefAcquireSpinLockAtDpcLevel ; acquire current PRCB lock
endif
;
; If a thread had been scheduled for this processor but was removed from
; eligibility (e.g., an affinity change), then the new thread could be the
; idle thread.
;
kid33: mov esi, [ebx].PcPrcbData.PbNextThread ; get next thread address
ifndef NT_UP
cmp esi, edi ; check if idle thread
je short kisame ; if e, processor idle again
endif
and dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; clear next thread
mov [ebx].PcPrcbData.PbCurrentThread, esi ; set new thread address
mov byte ptr [esi]+ThState, Running ; set thread state running
;
; Clear idle schedule since a new thread has been selected for execution on
; this processor and release the PRCB lock.
;
ifndef NT_UP
and byte ptr [ebx].PcPrcbData.PbIdleSchedule, 0 ; clear idle schedule
and dword ptr [ebx].PcPrcbData.PbPrcbLock, 0 ; release current PRCB lock
endif
kid35: ;
CAPSTART <@KiIdleLoop@0,SwapContext>
mov ecx, APC_LEVEL ; set APC bypass disable
call SwapContext ; swap context
CAPEND <@KiIdleLoop@0>
ifndef NT_UP
LowerIrql DISPATCH_LEVEL ; lower IRQL to dispatch level
endif
jmp kid30 ;
;
; The new thread is the Idle thread (same as old thread). This can happen
; rarely when a thread scheduled for this processor is made unable to run
; on this processor. As this processor has again been marked idle, other
; processors may unconditionally assign new threads to this processor.
;
ifndef NT_UP
kisame: and dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; clear next thread
and dword ptr [ebx].PcPrcbData.PbPrcbLock, 0 ; release current PRCB lock
and byte ptr [edi].ThSwapBusy, 0 ; set idle thread context swap idle
jmp kid30 ;
;
; Call idle schedule if requested.
;
kid40: cmp byte ptr [ebx].PcPrcbData.PbIdleSchedule, 0 ; check if idle schedule
je kid10 ; if e, idle schedule not requested
sti ; enable interrupts
lea ecx, [ebx].PcPrcbData ; get current PRCB address
fstCall KiIdleSchedule ; attempt to schedule thread
test eax, eax ; test if new thread schedule
mov esi, eax ; set new thread address
mov edi, [ebx].PcPrcbData.PbIdleThread ; get idle thread address
jnz short kid35 ; if nz, new thread scheduled
jmp kid30 ;
endif
fstENDP KiIdleLoop
1: kd> g
Breakpoint 14 hit
eax=00000041 ebx=ba582cc8 ecx=8952bc18 edx=80010031 esi=00000000 edi=804edc60
eip=80b00720 esp=ba582c1c ebp=ba582c20 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt:
80b00720 648b1d1c000000 mov ebx,dword ptr fs:[1Ch] fs:0030:0000001c=f7737000
1: kd> kc 5
00 nt!KiDispatchInterrupt
01 hal!HalpDispatchInterrupt
02 hal!KfLowerIrql
03 nt!KiSwapThread
04 nt!KeDelayExecutionThread
1: kd> dx -id 0,0,89831250 -r1 ((basesrv!_KPRCB *)0xf7737120)
((basesrv!_KPRCB *)0xf7737120) : 0xf7737120 [Type: _KPRCB *]
+0x000\] MinorVersion : 0x1 \[Type: unsigned short
+0x002\] MajorVersion : 0x1 \[Type: unsigned short
+0x004\] CurrentThread : 0x8952bc18 \[Type: _KTHREAD \*
+0x008\] NextThread : 0x0 \[Type: _KTHREAD \*
+0x00c\] IdleThread : 0xf7739fa0 \[Type: _KTHREAD \*
+0x928\] ReadySummary : 0x0 \[Type: unsigned long
1: kd> kc
00 nt!KiDispatchInterrupt
01 hal!HalpDispatchInterrupt
02 hal!KfLowerIrql
03 nt!KiSwapThread
04 nt!KeDelayExecutionThread
05 nt!NtDelayExecution
06 nt!_KiSystemService
07 SharedUserData!SystemCallStub
08 ntdll!ZwDelayExecution
09 KERNEL32!SleepEx
0a KERNEL32!Sleep
WARNING: Frame IP not in any known module. Following frames may be wrong.
0b 0x0
0c 0x0
0d KERNEL32!BaseThreadStart
1: kd> .process
Implicit process is now 89802bf8
1: kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 899a2278 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 0a200000 ObjectTable: e1000e38 HandleCount: 319.
Image: System
PROCESS 89802bf8 SessionId: 0 Cid: 04b4 Peb: 7ffdf000 ParentCid: 01f4
DirBase: 7a00c000 ObjectTable: e164aa80 HandleCount: 165.
Image: msdtc.exe
1: kd> p
eax=00000041 ebx=f7737000 ecx=8952bc18 edx=80010031 esi=00000000 edi=804edc60
eip=80b00727 esp=ba582c1c ebp=ba582c20 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt+0x7:
80b00727 fa cli
1: kd> p
eax=00000041 ebx=f7737000 ecx=8952bc18 edx=80010031 esi=00000000 edi=804edc60
eip=80b00728 esp=ba582c1c ebp=ba582c20 iopl=0 nv up di pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000046
nt!KiDispatchInterrupt+0x8:
80b00728 8b838c090000 mov eax,dword ptr [ebx+98Ch] ds:0023:f773798c=00000000
1: kd> p
eax=00000000 ebx=f7737000 ecx=8952bc18 edx=80010031 esi=00000000 edi=804edc60
eip=80b0072e esp=ba582c1c ebp=ba582c20 iopl=0 nv up di pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000046
nt!KiDispatchInterrupt+0xe:
80b0072e 0b83c8090000 or eax,dword ptr [ebx+9C8h] ds:0023:f77379c8=00000000
1: kd> p
eax=00000000 ebx=f7737000 ecx=8952bc18 edx=80010031 esi=00000000 edi=804edc60
eip=80b00734 esp=ba582c1c ebp=ba582c20 iopl=0 nv up di pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000046
nt!KiDispatchInterrupt+0x14:
80b00734 0b83500b0000 or eax,dword ptr [ebx+0B50h] ds:0023:f7737b50=00000000
1: kd> p
eax=00000000 ebx=f7737000 ecx=8952bc18 edx=80010031 esi=00000000 edi=804edc60
eip=80b0073a esp=ba582c1c ebp=ba582c20 iopl=0 nv up di pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000046
nt!KiDispatchInterrupt+0x1a:
80b0073a 741e je nt!KiDispatchInterrupt+0x3a (80b0075a) [br=1]
1: kd> p
eax=00000000 ebx=f7737000 ecx=8952bc18 edx=80010031 esi=00000000 edi=804edc60
eip=80b0075a esp=ba582c1c ebp=ba582c20 iopl=0 nv up di pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000046
nt!KiDispatchInterrupt+0x3a:
80b0075a fb sti
1: kd> p
Breakpoint 45 hit
eax=00000000 ebx=f7737000 ecx=8952bc18 edx=80010031 esi=00000000 edi=804edc60
eip=80b0075b esp=ba582c1c ebp=ba582c20 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt+0x3b:
80b0075b 80bbe109000000 cmp byte ptr [ebx+9E1h],0 ds:0023:f77379e1=00
1: kd> p
eax=00000000 ebx=f7737000 ecx=8952bc18 edx=80010031 esi=00000000 edi=804edc60
eip=80b00762 esp=ba582c1c ebp=ba582c20 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt+0x42:
80b00762 7577 jne nt!KiDispatchInterrupt+0xbb (80b007db) [br=0]
1: kd> p
eax=00000000 ebx=f7737000 ecx=8952bc18 edx=80010031 esi=00000000 edi=804edc60
eip=80b00764 esp=ba582c1c ebp=ba582c20 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt+0x44:
80b00764 83bb2801000000 cmp dword ptr [ebx+128h],0 ds:0023:f7737128=00000000
1: kd> p
eax=00000000 ebx=f7737000 ecx=8952bc18 edx=80010031 esi=00000000 edi=804edc60
eip=80b0076b esp=ba582c1c ebp=ba582c20 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt+0x4b:
80b0076b 746d je nt!KiDispatchInterrupt+0xba (80b007da) [br=1]
1: kd> p
eax=00000000 ebx=f7737000 ecx=8952bc18 edx=80010031 esi=00000000 edi=804edc60
eip=80b007da esp=ba582c1c ebp=ba582c20 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt+0xba:
80b007da c3 ret
没有任何任务需要做。