Leaked source code of windows server 2003
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.

275 lines
8.0 KiB

  1. title "Idle Loop"
  2. ;++
  3. ;
  4. ; Copyright (c) 2000 Microsoft Corporation
  5. ;
  6. ; Module Name:
  7. ;
  8. ; idle.asm
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module implements the platform specifid idle loop.
  13. ;
  14. ; Author:
  15. ;
  16. ; David N. Cutler (davec) 21-Sep-2000
  17. ;
  18. ; Environment:
  19. ;
  20. ; Kernel mode only.
  21. ;
  22. ;--
  23. include ksamd64.inc
  24. extern KdDebuggerEnabled:byte
  25. extern KeAcquireQueuedSpinLockAtDpcLevel:proc
  26. extern KeAcquireQueuedSpinLockRaiseToSynch:proc
  27. extern KeReleaseQueuedSpinLock:proc
  28. extern KeReleaseQueuedSpinLockFromDpcLevel:proc
  29. extern KdCheckForDebugBreak:proc
  30. ifndef NT_UP
  31. extern KiIdleSchedule:proc
  32. endif
  33. extern KiIdleSummary:qword
  34. extern KiRetireDpcList:proc
  35. extern SwapContext:proc
  36. extern __imp_HalClearSoftwareInterrupt:qword
  37. subttl "Idle Loop"
  38. ;++
  39. ; VOID
  40. ; KiIdleLoop (
  41. ; VOID
  42. ; )
  43. ;
  44. ; Routine Description:
  45. ;
  46. ; This routine continuously executes the idle loop and never returns.
  47. ;
  48. ; Arguments:
  49. ;
  50. ; None.
  51. ;
  52. ; Return value:
  53. ;
  54. ; This routine never returns.
  55. ;
  56. ;--
  57. IlFrame struct
  58. P1Home dq ? ;
  59. P2Home dq ? ;
  60. P3Home dq ? ;
  61. P4Home dq ? ;
  62. Fill dq ? ; fill to 8 mod 16
  63. IlFrame ends
  64. NESTED_ENTRY KiIdleLoop, _TEXT$00
  65. alloc_stack (sizeof IlFrame) ; allocate stack frame
  66. END_PROLOGUE
  67. mov rbx, gs:[PcCurrentPrcb] ; get current processor block address
  68. xor edi, edi ; reset check breakin counter
  69. jmp short KiIL20 ; skip idle processor on first iteration
  70. ;
  71. ; There are no entries in the DPC list and a thread has not been selected
  72. ; for execution on this processor. Call the HAL so power managment can be
  73. ; performed.
  74. ;
  75. ; N.B. The HAL is called with interrupts disabled. The HAL will return
  76. ; with interrupts enabled.
  77. ;
  78. KiIL10: lea rcx, PbPowerState[rbx] ; set address of power state
  79. call qword ptr PpIdleFunction[rcx] ; call idle function
  80. ;
  81. ; Give the debugger an opportunity to gain control if the kernel debuggger
  82. ; is enabled.
  83. ;
  84. ; N.B. On an MP system the lowest numbered idle processor is the only
  85. ; processor that checks for a breakin request.
  86. ;
  87. KiIL20: cmp KdDebuggerEnabled, 0 ; check if a debugger is enabled
  88. je short CheckDpcList ; if e, debugger not enabled
  89. ifndef NT_UP
  90. mov rax, KiIdleSummary ; get idle summary
  91. mov rcx, PbSetMember[rbx] ; get set member
  92. dec rcx ; compute right bit mask
  93. and rax, rcx ; check if any lower bits set
  94. jnz short CheckDpcList ; if nz, not lowest numbered
  95. endif
  96. dec edi ; decrement check breakin counter
  97. jg short CheckDpcList ; if g, not time to check for breakin
  98. call KdCheckForDebugBreak ; check if break in requested
  99. mov edi, 1000 ; set check breakin interval
  100. ;
  101. ; Disable interrupts and check if there is any work in the DPC list of the
  102. ; current processor or a target processor.
  103. ;
  104. ; N.B. The following code enables interrupts for a few cycles, then disables
  105. ; them again for the subsequent DPC and next thread checks.
  106. ;
  107. CheckDpcList: ; reference label
  108. sti ; enable interrupts
  109. nop ;
  110. nop ;
  111. cli ; disable interrupts
  112. ;
  113. ; Process the deferred procedure call list for the current processor.
  114. ;
  115. mov eax, PbDpcQueueDepth[rbx] ; get DPC queue depth
  116. or rax, PbTimerRequest[rbx] ; merge timer request value
  117. ifndef NT_UP
  118. or rax, PbDeferredReadyListHead[rbx] ; merge ready list head
  119. endif
  120. jz short CheckNextThread ; if z, no DPCs to process
  121. mov cl, DISPATCH_LEVEL ; set interrupt level
  122. call __imp_HalClearSoftwareInterrupt ; clear software interrupt
  123. mov rcx, rbx ; set current PRCB address
  124. call KiRetireDpcList ; process the current DPC list
  125. xor edi, edi ; clear check breakin interval
  126. ;
  127. ; Check if a thread has been selected to run on the current processor.
  128. ;
  129. CheckNextThread: ;
  130. cmp qword ptr PbNextThread[rbx], 0 ; check if thread slected
  131. ifdef NT_UP
  132. je short KiIL10 ; if e, no thread selected
  133. else
  134. je KiIL50 ; if e, no thread selected
  135. endif
  136. sti ; enable interrupts
  137. mov ecx, SYNCH_LEVEL ; set IRQL to synchronization level
  138. RaiseIrql ;
  139. ;
  140. ; set context swap busy for the idle thread and acquire the PRCB Lock.
  141. ;
  142. mov rdi, PbCurrentThread[rbx] ; get current thread address
  143. ifndef NT_UP
  144. mov byte ptr ThSwapBusy[rdi], 1 ; set ocntext swap busy
  145. lea r11, PbPrcbLock[rbx] ; set address of current PRCB lock
  146. AcquireSpinLock r11 ; acquire current PRCB Lock
  147. endif
  148. mov rsi, PbNextThread[rbx] ; set next thread address
  149. ;
  150. ; If a thread had been scheduled for this processor, but was removed from
  151. ; eligibility (e.g., an affinity change), then the new thread could be the
  152. ; idle thread.
  153. ;
  154. ifndef NT_UP
  155. cmp rsi, rdi ; check if swap from idle to idle
  156. je short KiIL40 ; if eq, idle to idle
  157. endif
  158. and qword ptr PbNextThread[rbx], 0 ; clear next thread address
  159. mov PbCurrentThread[rbx], rsi ; set current thread address
  160. mov byte ptr ThState[rsi], Running ; set new thread state
  161. ;
  162. ; Clear idle schedule since a new thread has been selected for execution on
  163. ; this processor and release the PRCB lock.
  164. ;
  165. ifndef NT_UP
  166. and byte ptr PbIdleSchedule[rbx], 0 ; clear idle schedule
  167. and qword ptr PbPrcbLock[rbx], 0 ; release current PRCB lock
  168. endif
  169. ;
  170. ; Switch context to new thread.
  171. ;
  172. KiIL30: mov cl, APC_LEVEL ; set APC bypass disable
  173. call SwapContext ; swap context to next thread
  174. ifndef NT_UP
  175. mov ecx, DISPATCH_LEVEL ; set IRQL to dispatch level
  176. SetIrql ;
  177. endif
  178. xor edi, edi ; clear check breakin interval
  179. jmp KiIL20 ; loop
  180. ;
  181. ; The new thread is the Idle thread (same as old thread). This can happen
  182. ; rarely when a thread scheduled for this processor is made unable to run
  183. ; on this processor. As this processor has again been marked idle, other
  184. ; processors may unconditionally assign new threads to this processor.
  185. ;
  186. ifndef NT_UP
  187. KiIL40: and qword ptr PbNextThread[rbx], 0 ; clear next thread
  188. and qword ptr PbPrcbLock[rbx], 0 ; release current PRCB lock
  189. and byte ptr ThSwapBusy[rdi], 0 ; set context swap idle
  190. jmp KiIL20 ;
  191. ;
  192. ; Call idle schedule if requested.
  193. ;
  194. KiIL50: cmp byte ptr PbIdleSchedule[rbx], 0 ; check if idle schedule
  195. je KiIL10 ; if e, idle schedule not requested
  196. sti ; enable interrupts
  197. mov rcx, rbx ; pass current PRCB address
  198. call KiIdleSchedule ; attempt to schedule thread
  199. test rax, rax ; test if new thread schedule
  200. mov rsi, rax ; set new thread address
  201. mov rdi, PbIdleThread[rbx] ; get idle thread address
  202. jnz short KiIL30 ; if nz, new thread scheduled
  203. jmp KiIL20 ;
  204. endif
  205. NESTED_END KiIdleLoop, _TEXT$00
  206. end