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.

1642 lines
47 KiB

  1. title "Context Swap"
  2. ;++
  3. ;
  4. ; Copyright (c) 1989, 2000 Microsoft Corporation
  5. ;
  6. ; Module Name:
  7. ;
  8. ; ctxswap.asm
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module implements the code necessary to field the dispatch
  13. ; interrupt and to perform kernel initiated context switching.
  14. ;
  15. ; Author:
  16. ;
  17. ; Shie-Lin Tzong (shielint) 14-Jan-1990
  18. ;
  19. ; Environment:
  20. ;
  21. ; Kernel mode only.
  22. ;
  23. ; Revision History:
  24. ;
  25. ; 22-feb-90 bryanwi
  26. ; write actual swap context procedure
  27. ;
  28. ;--
  29. .586p
  30. .xlist
  31. include ks386.inc
  32. include i386\kimacro.inc
  33. include mac386.inc
  34. include callconv.inc
  35. include irqli386.inc
  36. FPOFRAME macro a, b
  37. .FPO ( a, b, 0, 0, 0, 0 )
  38. endm
  39. .list
  40. EXTRNP KefAcquireSpinLockAtDpcLevel,1,,FASTCALL
  41. EXTRNP KefReleaseSpinLockFromDpcLevel,1,,FASTCALL
  42. EXTRNP HalClearSoftwareInterrupt,1,IMPORT,FASTCALL
  43. EXTRNP HalRequestSoftwareInterrupt,1,IMPORT,FASTCALL
  44. ifndef NT_UP
  45. EXTRNP KiIdleSchedule,1,,FASTCALL
  46. endif
  47. EXTRNP KiQueueReadyThread,2,,FASTCALL
  48. EXTRNP KiRetireDpcList,1,,FASTCALL
  49. EXTRNP _KiQuantumEnd,0
  50. EXTRNP _KiTimerExpiration,4
  51. EXTRNP _KeBugCheckEx,5
  52. extrn _KiTrap13:PROC
  53. extrn _KeFeatureBits:DWORD
  54. extrn __imp__KeRaiseIrqlToSynchLevel@0:DWORD
  55. extrn _KiIdleSummary:DWORD
  56. EXTRNP WmiTraceContextSwap,2,,FASTCALL
  57. if DBG
  58. extrn _KdDebuggerEnabled:BYTE
  59. EXTRNP _DbgBreakPoint,0
  60. EXTRNP _KdPollBreakIn,0
  61. extrn _DbgPrint:near
  62. extrn _MsgDpcTrashedEsp:BYTE
  63. extrn _MsgDpcTimeout:BYTE
  64. extrn _KiDPCTimeout:DWORD
  65. endif
  66. _TEXT$00 SEGMENT PARA PUBLIC 'CODE'
  67. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  68. cPublicFastCall KiRDTSC, 1
  69. rdtsc ; read the timestamp counter
  70. mov [ecx], eax ; return the low 32 bits
  71. mov [ecx+4], edx ; return the high 32 bits
  72. fstRET KiRDTSC
  73. fstENDP KiRDTSC
  74. page ,132
  75. subttl "Swap Context"
  76. ;++
  77. ;
  78. ; BOOLEAN
  79. ; KiSwapContext (
  80. ; IN PKTHREAD OldThread
  81. ; IN PKTHREAD NewThread
  82. ; )
  83. ;
  84. ; Routine Description:
  85. ;
  86. ; This function is a small wrapper, callable from C code, that marshalls
  87. ; arguments and calls the actual swap context routine.
  88. ;
  89. ; Arguments:
  90. ;
  91. ; OldThread (ecx) - Supplies the address of the old thread
  92. ; NewThread (edx) - Supplies the address of the new thread.
  93. ;
  94. ; Return Value:
  95. ;
  96. ; If a kernel APC is pending, then a value of TRUE is returned. Otherwise,
  97. ; a value of FALSE is returned.
  98. ;
  99. ;--
  100. cPublicFastCall KiSwapContext, 2
  101. .fpo (0, 0, 0, 4, 1, 0)
  102. ;
  103. ; N.B. The following registers MUST be saved such that ebp is saved last.
  104. ; This is done so the debugger can find the saved ebp for a thread
  105. ; that is not currently in the running state.
  106. ;
  107. sub esp, 4*4
  108. mov [esp+12], ebx ; save registers
  109. mov [esp+8], esi ;
  110. mov [esp+4], edi ;
  111. mov [esp+0], ebp ;
  112. mov ebx, PCR[PcSelfPcr] ; set address of PCR
  113. mov edi, ecx ; set old thread address
  114. mov esi, edx ; set next thread address
  115. movzx ecx, byte ptr [edi].ThWaitirql ; set APC interrupt bypass disable
  116. CAPSTART <@KiSwapContext@8,SwapContext>
  117. call SwapContext ; swap context
  118. CAPEND <@KiSwapContext@8>
  119. mov ebp, [esp+0] ; restore registers
  120. mov edi, [esp+4] ;
  121. mov esi, [esp+8] ;
  122. mov ebx, [esp+12] ;
  123. add esp, 4*4 ;
  124. fstRET KiSwapContext ;
  125. fstENDP KiSwapContext
  126. page ,132
  127. subttl "Dispatch Interrupt"
  128. ;++
  129. ;
  130. ; Routine Description:
  131. ;
  132. ; This routine is entered as the result of a software interrupt generated
  133. ; at DISPATCH_LEVEL. Its function is to process the Deferred Procedure Call
  134. ; (DPC) list, and then perform a context switch if a new thread has been
  135. ; selected for execution on the processor.
  136. ;
  137. ; This routine is entered at IRQL DISPATCH_LEVEL with the dispatcher
  138. ; database unlocked. When a return to the caller finally occurs, the
  139. ; IRQL remains at DISPATCH_LEVEL, and the dispatcher database is still
  140. ; unlocked.
  141. ;
  142. ; Arguments:
  143. ;
  144. ; None
  145. ;
  146. ; Return Value:
  147. ;
  148. ; None.
  149. ;
  150. ;--
  151. align 16
  152. cPublicProc _KiDispatchInterrupt ,0
  153. cPublicFpo 0, 0
  154. mov ebx, PCR[PcSelfPcr] ; get address of PCR
  155. ;
  156. ; Disable interrupts and check if there is any work in the DPC list
  157. ; of the current processor.
  158. ;
  159. kdi00: cli ; disable interrupts
  160. mov eax, [ebx]+PcPrcbData+PbDpcQueueDepth ; get DPC queue depth
  161. or eax, [ebx]+PcPrcbData+PbTimerRequest ; merge timer request
  162. ifndef NT_UP
  163. or eax, [ebx]+PcPrcbData+PbDeferredReadyListHead ; merge deferred list head
  164. endif
  165. jz short kdi40 ; if z, no DPC's or timers to process
  166. push ebp ; save register
  167. ;
  168. ; Exceptions occuring in DPCs are unrelated to any exception handlers
  169. ; in the interrupted thread. Terminate the exception list.
  170. ;
  171. push [ebx].PcExceptionList
  172. mov [ebx].PcExceptionList, EXCEPTION_CHAIN_END
  173. ;
  174. ; Switch to the DPC stack for this processor.
  175. ;
  176. mov edx, esp
  177. mov esp, [ebx].PcPrcbData.PbDpcStack
  178. push edx
  179. .fpo (0, 0, 0, 1, 1, 0)
  180. mov ecx, [ebx].PcPrcb ; get current PRCB address
  181. CAPSTART <_KiDispatchInterrupt,@KiRetireDpcList@4>
  182. fstCall KiRetireDpcList ; process the current DPC list
  183. CAPEND <_KiDispatchInterrupt>
  184. ;
  185. ; Switch back to the current thread stack, restore the exception list
  186. ; and saved EBP.
  187. ;
  188. pop esp
  189. pop [ebx].PcExceptionList
  190. pop ebp
  191. .fpo (0, 0, 0, 0, 0, 0)
  192. ;
  193. ; Check to determine if quantum end is requested.
  194. ;
  195. ; N.B. If a new thread is selected as a result of processing the quantum
  196. ; end request, then the new thread is returned with the dispatcher
  197. ; database locked. Otherwise, NULL is returned with the dispatcher
  198. ; database unlocked.
  199. ;
  200. kdi40: sti ; enable interrupts
  201. cmp byte ptr [ebx].PcPrcbData.PbQuantumEnd, 0 ; quantum end requested
  202. jne kdi90 ; if neq, quantum end request
  203. ;
  204. ; Check to determine if a new thread has been selected for execution on this
  205. ; processor.
  206. ;
  207. cmp dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; check if next thread
  208. je kdi70 ; if eq, then no new thread
  209. ;
  210. ; N.B. The following registers MUST be saved such that ebp is saved last.
  211. ; This is done so the debugger can find the saved ebp for a thread
  212. ; that is not currently in the running state.
  213. ;
  214. .fpo (0, 0, 0, 3, 1, 0)
  215. sub esp, 3*4
  216. mov [esp+8], esi ; save registers
  217. mov [esp+4], edi ;
  218. mov [esp+0], ebp ;
  219. mov edi, [ebx].PcPrcbData.PbCurrentThread ; get current thread address (as old thread)
  220. ;
  221. ; Raise IRQL to SYNCH level, set context swap busy for the old thread, and
  222. ; acquire the current PRCB lock.
  223. ;
  224. ifndef NT_UP
  225. call dword ptr [__imp__KeRaiseIrqlToSynchLevel@0] ; raise IRQL to SYNCH
  226. mov byte ptr [edi].ThSwapBusy, 1 ; set context swap busy
  227. lea ecx, [ebx].PcPrcbData.PbPrcbLock ; get PRCB lock address
  228. lock bts dword ptr [ecx], 0 ; try to acquire PRCB lock
  229. jnc short kdi50 ; if nc, PRCB lock acquired
  230. fstCall KefAcquireSpinLockAtDpcLevel ; acquire current PRCB lock
  231. endif
  232. ;
  233. ; Get the next thread address, set the thread state to running, queue the old
  234. ; running thread, and swap context to the next thread.
  235. ;
  236. kdi50: mov esi, [ebx].PcPrcbData.PbNextThread ; get next thread address
  237. and dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; clear next thread address
  238. mov [ebx].PcPrcbData.PbCurrentThread, esi ; set current thread address
  239. mov byte ptr [esi]+ThState, Running ; set thread state to running
  240. mov byte ptr [edi].ThWaitReason, WrDispatchInt ; set wait reason
  241. mov ecx, edi ; set address of curent thread
  242. lea edx, [ebx].PcPrcbData ; set address of PRCB
  243. fstCall KiQueueReadyThread ; ready thread for execution
  244. CAPSTART <_KiDispatchInterrupt,SwapContext>
  245. mov cl, APC_LEVEL ; set APC interrupt bypass disable
  246. call SwapContext ; swap context
  247. CAPEND <_KiDispatchInterrupt>
  248. mov ebp, [esp+0] ; restore registers
  249. mov edi, [esp+4] ;
  250. mov esi, [esp+8] ;
  251. add esp, 3*4
  252. kdi70: stdRET _KiDispatchInterrupt ; return
  253. ;
  254. ; Process quantum end event.
  255. ;
  256. ; N.B. If the quantum end code returns a NULL value, then no next thread
  257. ; has been selected for execution. Otherwise, a next thread has been
  258. ; selected and the source thread lock has been acquired.
  259. ;
  260. kdi90: mov byte ptr [ebx].PcPrcbData.PbQuantumEnd, 0 ; clear quantum end indicator
  261. CAPSTART <_KiDispatchInterrupt,_KiQuantumEnd@0>
  262. stdCall _KiQuantumEnd ; process quantum end
  263. CAPEND <_KiDispatchInterrupt>
  264. stdRET _KiDispatchInterrupt ; return
  265. stdENDP _KiDispatchInterrupt
  266. page ,132
  267. subttl "Swap Context to Next Thread"
  268. ;++
  269. ;
  270. ; Routine Description:
  271. ;
  272. ; This routine is called to swap context from one thread to the next.
  273. ; It swaps context, flushes the data, instruction, and translation
  274. ; buffer caches, restores nonvolatile integer registers, and returns
  275. ; to its caller.
  276. ;
  277. ; N.B. It is assumed that the caller (only callers are within this
  278. ; module) saved the nonvolatile registers, ebx, esi, edi, and
  279. ; ebp. This enables the caller to have more registers available.
  280. ;
  281. ; Arguments:
  282. ;
  283. ; cl - APC interrupt bypass disable (zero enable, nonzero disable).
  284. ; edi - Address of previous thread.
  285. ; esi - Address of next thread.
  286. ; ebx - Address of PCR.
  287. ;
  288. ; Return value:
  289. ;
  290. ; al - Kernel APC pending.
  291. ; ebx - Address of PCR.
  292. ; esi - Address of current thread object.
  293. ;
  294. ;--
  295. ;
  296. ; NOTE: The ES: override on the move to ThState is part of the
  297. ; lazy-segment load system. It assures that ES has a valid
  298. ; selector in it, thus preventing us from propagating a bad
  299. ; ES across a context switch.
  300. ;
  301. ; Note that if segments, other than the standard flat segments,
  302. ; with limits above 2 gig exist, neither this nor the rest of
  303. ; lazy segment loads are reliable.
  304. ;
  305. ; Note that ThState must be set before the dispatcher lock is released
  306. ; to prevent KiSetPriorityThread from seeing a stale value.
  307. ;
  308. ifndef NT_UP
  309. public _ScPatchFxb
  310. public _ScPatchFxe
  311. endif
  312. public SwapContext
  313. align 16
  314. SwapContext proc
  315. ;
  316. ; Save the APC disable flag.
  317. ;
  318. push ecx ; save APC bypass disable
  319. cPublicFpo 0, 1
  320. ;
  321. ; Wait for context to be swapped for the target thread.
  322. ;
  323. ifndef NT_UP
  324. sc00: cmp byte ptr [esi].ThSwapBusy, 0 ; check if context swap busy
  325. je short sc01 ; if e, context swap idle
  326. YIELD ; yield execution for SMT system
  327. jmp short sc00 ;
  328. endif
  329. ;
  330. ; Increment the number of context switches on this processor.
  331. ;
  332. ; N.B. This increment is done here is force the cache block containing the
  333. ; context switch count into the cache as write exclusive. There are
  334. ; several other references to this cache block in the following code.
  335. ;
  336. sc01: inc dword ptr [ebx]+PcContextSwitches ; processor count
  337. ;
  338. ; Save the thread exception list head.
  339. ;
  340. push [ebx]+PcExceptionList ; save thread exception list head
  341. cPublicFpo 0, 2
  342. ;
  343. ; Check for context swap logging.
  344. ;
  345. cmp [ebx]+PcPerfGlobalGroupMask, 0 ; check if logging enable
  346. jne sc92 ; If not, then check if we are enabled
  347. sc03:
  348. ifndef NT_UP
  349. if DBG
  350. mov cl, [esi]+ThNextProcessor ; get current processor number
  351. cmp cl, [ebx]+PcPrcbData+PbNumber ; same as running processor?
  352. jne sc_error2 ; if ne, processor number mismatch
  353. endif
  354. endif
  355. ;
  356. ; Accumulate the total time spent in a thread.
  357. ;
  358. ifdef PERF_DATA
  359. test _KeFeatureBits, KF_RDTSC ; feature supported?
  360. jz short @f ; if z, feature not present
  361. rdtsc ; read cycle counter
  362. sub eax, [ebx].PcPrcbData.PbThreadStartCount.LiLowPart ; sub off thread
  363. sbb edx, [ebx].PcPrcbData.PbThreadStartCount.LiHighPart ; starting time
  364. add [edi].EtPerformanceCountLow, eax ; accumlate thread run time
  365. adc [edi].EtPerformanceCountHigh, edx ;
  366. add [ebx].PcPrcbData.PbThreadStartCount.LiLowPart, eax ; set new thread
  367. adc [ebx].PcPrcbData.PbThreadStartCount.LiHighPart, edx ; starting time
  368. @@: ;
  369. endif
  370. ;
  371. ; On a uniprocessor system the NPX state is swapped in a lazy manner.
  372. ; If a thread whose state is not in the coprocessor attempts to perform
  373. ; a coprocessor operation, the current NPX state is swapped out (if needed),
  374. ; and the new state is swapped in durning the fault. (KiTrap07)
  375. ;
  376. ; On a multiprocessor system we still fault in the NPX state on demand, but
  377. ; we save the state when the thread switches out (assuming the NPX state
  378. ; was loaded). This is because it could be difficult to obtain the thread's
  379. ; NPX in the trap handler if it was loaded into a different processor's
  380. ; coprocessor.
  381. ;
  382. mov ebp, cr0 ; get current CR0
  383. mov edx, ebp ;
  384. ifndef NT_UP
  385. cmp byte ptr [edi]+ThNpxState, NPX_STATE_LOADED ; check if NPX state
  386. je sc_save_npx_state ; if e, NPX state not loaded
  387. endif
  388. ;
  389. ; Save the old stack pointer and compute the new stack limits.
  390. ;
  391. sc05: mov [edi]+ThKernelStack, esp ; save old kernel stack pointer
  392. mov eax, [esi]+ThInitialStack ; get new initial stack pointer
  393. ;
  394. ; (eax) = Initial Stack
  395. ; (ebx) = PCR
  396. ; (edi) = OldThread
  397. ; (esi) = NewThread
  398. ; (ebp) = Current CR0
  399. ; (edx) = Current CR0
  400. ;
  401. .errnz (NPX_STATE_NOT_LOADED - CR0_TS - CR0_MP)
  402. .errnz (NPX_STATE_LOADED - 0)
  403. ifdef NT_UP
  404. ;
  405. ; On UP systems floating point state might be being changed by an ISR so we
  406. ; block interrupts.
  407. ;
  408. cli
  409. endif
  410. movzx ecx, byte ptr [esi]+ThNpxState ; new NPX state is (or is not) loaded
  411. and edx, NOT (CR0_MP+CR0_EM+CR0_TS) ; clear thread settable NPX bits
  412. or ecx, edx ; or in new thread's cr0
  413. or ecx, [eax]+FpCr0NpxState-NPX_FRAME_LENGTH ; merge new thread settable state
  414. cmp ebp, ecx ; check if old and new CR0 match
  415. jne sc_reload_cr0 ; if ne, change in CR0
  416. sc06:
  417. ifdef NT_UP
  418. sti
  419. endif
  420. if DBG
  421. mov eax, [esi]+ThKernelStack ; set new stack pointer
  422. cmp esi, dword ptr [eax-4]
  423. je @f
  424. int 3
  425. @@:
  426. xchg esp, eax
  427. mov [eax-4], edi ; Save thread address on stack below stack pointer
  428. else
  429. mov esp, [esi]+ThKernelStack ; set new stack pointer
  430. endif
  431. ;
  432. ; Check if the old process is the same as the new process.
  433. ;
  434. mov ebp, [esi].ThApcState.AsProcess ; get old process address
  435. mov eax, [edi].ThApcState.AsProcess ; get old process address
  436. cmp ebp, eax ; check if process match
  437. jz short sc23 ; if z, process match
  438. ;
  439. ; Set the processor bit in the new process and clear the old.
  440. ;
  441. ifndef NT_UP
  442. mov ecx, [ebx]+PcSetMemberCopy ; get processor set member
  443. lock xor [ebp]+PrActiveProcessors, ecx ; set bit in new processor set
  444. lock xor [eax]+PrActiveProcessors, ecx ; clear bit in old processor set
  445. if DBG
  446. test [ebp]+PrActiveProcessors, ecx ; test if bit set in new set
  447. jz sc_error5 ; if z, bit not set in new set
  448. test [eax]+PrActiveProcessors, ecx ; test if bit clear in old set
  449. jnz sc_error4 ; if nz, bit not clear in old set
  450. endif
  451. endif
  452. ;
  453. ; LDT switch, If either the target or source process have an LDT we need to
  454. ; load the ldt
  455. ;
  456. mov ecx, [ebp]+PrLdtDescriptor
  457. or ecx, [eax]+PrLdtDescriptor
  458. jnz sc_load_ldt ; if nz, LDT limit
  459. sc_load_ldt_ret:
  460. ;
  461. ; Load the new CR3 and as a side effect flush non-global TB entries.
  462. ;
  463. mov eax, [ebp]+PrDirectoryTableBase ; get new directory base
  464. mov cr3, eax ; and flush TB
  465. ;
  466. ; Set context swap idle for the old thread.
  467. ;
  468. sc23: ;
  469. ifndef NT_UP
  470. and byte ptr [edi].ThSwapBusy, 0 ; clear old thread swap busy
  471. endif
  472. xor eax, eax
  473. mov gs, eax
  474. ;
  475. ; Set the TEB descriptor to point to the thread TEB and set the TEB address
  476. ; in the PCR. The es override here is to force lazy segment loading to occure.
  477. ;
  478. mov eax, es:[esi]+ThTeb ; get user TEB address
  479. mov [ebx]+PcTeb, eax ; set user TEB address
  480. mov ecx, [ebx]+PcGdt ; get GDT address
  481. mov [ecx]+(KGDT_R3_TEB+KgdtBaseLow), ax ;
  482. shr eax, 16 ;
  483. mov [ecx]+(KGDT_R3_TEB+KgdtBaseMid), al ;
  484. mov [ecx]+(KGDT_R3_TEB+KgdtBaseHi), ah ;
  485. ;
  486. ; Adjust the initial stack address, if necessary, and store in the TSS so V86
  487. ; mode threads and 32 bit threads can share a common trapframe structure and
  488. ; the NPX save area will be accessible in the same manner on all threads.
  489. ;
  490. mov eax, [esi].ThInitialStack ; get initial stack address
  491. sub eax, NPX_FRAME_LENGTH
  492. .errnz (EFLAGS_V86_MASK AND 0FF00FFFFh)
  493. test byte ptr [eax] - KTRAP_FRAME_LENGTH + TsEFlags + 2, EFLAGS_V86_MASK / 10000h
  494. jnz short sc24 ; if nz, V86 frame, no adjustment
  495. sub eax, TsV86Gs - TsHardwareSegSs ; bias for missing fields
  496. sc24: mov ecx, [ebx]+PcTssCopy ; get TSS address
  497. mov [ecx]+TssEsp0, eax ; set initial kernel stack address
  498. ;
  499. ; Set the IOPM map offset value.
  500. ;
  501. ; N.B. This may be a redundant load of this value if the process did not
  502. ; change during the context switch. However, always reloading this
  503. ; value saves several instructions under the context swap lock.
  504. ;
  505. mov ax, [ebp]+PrIopmOffset ; set IOPM offset
  506. mov [ecx]+TssIoMapBase, ax ;
  507. ;
  508. ; Update context switch counters.
  509. ;
  510. inc dword ptr [esi]+ThContextSwitches ; thread count
  511. ;
  512. ; Restore thread exception list head and get APC bypass disable.
  513. ;
  514. pop [ebx].PcExceptionList ; restore thread exception list head
  515. pop ecx ; get APC bypass disable
  516. ;
  517. ; Check if an attempt is being made to context switch while in a DPC routine.
  518. ;
  519. cmp word ptr [ebx]+PcPrcbData+PbDpcRoutineActive, 0 ; check if DPC active
  520. jne sc91 ; bugcheck if DPC active.
  521. ;
  522. ; If the new thread has a kernel mode APC pending, then request an APC
  523. ; interrupt.
  524. ;
  525. cmp byte ptr [esi].ThApcState.AsKernelApcPending, 0 ; APC pending?
  526. jne short sc80 ; if ne, kernel APC pending
  527. xor eax, eax ; set return value
  528. ret ; return
  529. ;
  530. ; The new thread has an APC interrupt pending.
  531. ;
  532. ; If the the special APC disable count is nonzero, then return no kernel APC
  533. ; pending. An APC will be requested when the special APC disable count reaches
  534. ; zero.
  535. ;
  536. ; If APC interrupt bypass is not enabled, then request a software interrupt
  537. ; at APC_LEVEL and return no kernel APC pending. Otherwise, return kernel APC
  538. ; pending.
  539. ;
  540. sc80: cmp word ptr [esi].ThSpecialApcDisable, 0 ; check if special APC disable
  541. jne short sc90 ; if ne, special APC disable
  542. test cl, cl ; test for APC bypass disable
  543. jz short sc90 ; if z, APC bypass enabled
  544. mov cl, APC_LEVEL ; request software interrupt level
  545. fstCall HalRequestSoftwareInterrupt ;
  546. or eax, esp ; clear ZF flag
  547. sc90: setz al ; set return value
  548. ret ; return
  549. ;
  550. ; Set for new LDT value
  551. ;
  552. sc_load_ldt:
  553. mov eax, [ebp+PrLdtDescriptor] ;
  554. test eax, eax
  555. je @f
  556. mov ecx, [ebx]+PcGdt ; get GDT address
  557. mov [ecx+KGDT_LDT], eax ;
  558. mov eax, [ebp+PrLdtDescriptor+4] ;
  559. mov [ecx+KGDT_LDT+4], eax ;
  560. ;
  561. ; Set up int 21 descriptor of IDT. If the process does not have an Ldt, it
  562. ; should never make any int 21 calls. If it does, an exception is generated. If
  563. ; the process has an Ldt, we need to update int21 entry of LDT for the process.
  564. ; Note the Int21Descriptor of the process may simply indicate an invalid
  565. ; entry. In which case, the int 21 will be trapped to the kernel.
  566. ;
  567. mov ecx, [ebx]+PcIdt ;
  568. mov eax, [ebp+PrInt21Descriptor] ;
  569. mov [ecx+21h*8], eax ;
  570. mov eax, [ebp+PrInt21Descriptor+4] ;
  571. mov [ecx+21h*8+4], eax ;
  572. mov eax, KGDT_LDT
  573. @@: lldt ax
  574. jmp sc_load_ldt_ret
  575. ;
  576. ; Cr0 has changed (ie, floating point processor present), load the new value.
  577. ;
  578. sc_reload_cr0:
  579. if DBG
  580. test byte ptr [esi]+ThNpxState, NOT (CR0_TS+CR0_MP)
  581. jnz sc_error ;
  582. test dword ptr [eax]+FpCr0NpxState-NPX_FRAME_LENGTH, NOT (CR0_PE+CR0_MP+CR0_EM+CR0_TS)
  583. jnz sc_error3 ;
  584. endif
  585. mov cr0,ecx ; set new CR0 NPX state
  586. jmp sc06
  587. ;
  588. ; Save coprocessor's current context. FpCr0NpxState is the current thread's
  589. ; CR0 state. The following bits are valid: CR0_MP, CR0_EM, CR0_TS. MVDMs
  590. ; may set and clear MP & EM as they please and the settings will be reloaded
  591. ; on a context switch (but they will not be saved from CR0 to Cr0NpxState).
  592. ; The kernel sets and clears TS as required.
  593. ;
  594. ; (ebp) = Current CR0
  595. ; (edx) = Current CR0
  596. ;
  597. ifndef NT_UP
  598. sc_save_npx_state:
  599. and edx, NOT (CR0_MP+CR0_EM+CR0_TS) ; we need access to the NPX state
  600. mov ecx, [edi].ThInitialStack ; get NPX save save area address
  601. sub ecx, NPX_FRAME_LENGTH
  602. cmp ebp, edx ; Does CR0 need reloading?
  603. je short sc_npx10
  604. mov cr0, edx ; set new cr0
  605. mov ebp, edx ; (ebp) = (edx) = current cr0 state
  606. sc_npx10:
  607. ;
  608. ; The fwait following the fnsave is to make sure that the fnsave has stored the
  609. ; data into the save area before this coprocessor state could possibly be
  610. ; context switched in and used on a different (co)processor. I've added the
  611. ; clocks from when the dispatcher lock is released and don't believe it's a
  612. ; possibility. I've also timed the impact this fwait seems to have on a 486
  613. ; when performing lots of numeric calculations. It appears as if there is
  614. ; nothing to wait for after the fnsave (although the 486 manual says there is)
  615. ; and therefore the calculation time far outweighed the 3clk fwait and it
  616. ; didn't make a noticable difference.
  617. ;
  618. ;
  619. ; If FXSR feature is NOT present on the processor, the fxsave instruction is
  620. ; patched at boot time to start using fnsave instead
  621. ;
  622. _ScPatchFxb:
  623. ; fxsave [ecx] ; save NPX state
  624. db 0FH, 0AEH, 01
  625. _ScPatchFxe:
  626. mov byte ptr [edi]+ThNpxState, NPX_STATE_NOT_LOADED ; set no NPX state
  627. mov dword ptr [ebx].PcPrcbData+PbNpxThread, 0 ; clear npx owner
  628. jmp sc05
  629. endif
  630. ;
  631. ; This code is out of line to optimize the normal case with tracing is off.
  632. ;
  633. sc92: mov eax, [ebx]+PcPerfGlobalGroupMask ; Load the ptr into eax
  634. cmp eax, 0 ; catch race condition on pointer here
  635. jz sc03 ; instead of above in mainline code
  636. mov edx, esi ; pass the new ETHREAD object
  637. mov ecx, edi ; pass the old ETHREAD object
  638. test dword ptr [eax+PERF_CONTEXTSWAP_OFFSET], PERF_CONTEXTSWAP_FLAG
  639. jz sc03 ; return if our flag is not set
  640. fstCall WmiTraceContextSwap ; call the Wmi context swap trace
  641. jmp sc03 ;
  642. ;
  643. ; A context switch was attempted while executing a DPC - bug check.
  644. ;
  645. .fpo (2, 0, 0, 0, 0, 0)
  646. sc91: stdCall _KeBugCheckEx <ATTEMPTED_SWITCH_FROM_DPC, edi, esi, 0, 0>
  647. ret ; return
  648. if DBG
  649. sc_error5: int 3
  650. sc_error4: int 3
  651. sc_error3: int 3
  652. sc_error2: int 3
  653. sc_error: int 3
  654. endif
  655. SwapContext endp
  656. page , 132
  657. subttl "Flush EntireTranslation Buffer"
  658. ;++
  659. ;
  660. ; VOID
  661. ; KeFlushCurrentTb (
  662. ; )
  663. ;
  664. ; Routine Description:
  665. ;
  666. ; This function flushes the entire translation buffer (TB) on the current
  667. ; processor and also flushes the data cache if an entry in the translation
  668. ; buffer has become invalid.
  669. ;
  670. ; Arguments:
  671. ;
  672. ; Return Value:
  673. ;
  674. ; None.
  675. ;
  676. ;--
  677. cPublicProc _KeFlushCurrentTb ,0
  678. ktb00: mov eax, cr3 ; (eax) = directory table base
  679. mov cr3, eax ; flush TLB
  680. stdRET _KeFlushCurrentTb
  681. ktb_gb: mov eax, cr4 ; *** see Ki386EnableGlobalPage ***
  682. and eax, not CR4_PGE ; This FlushCurrentTb version gets copied into
  683. mov cr4, eax ; ktb00 at initialization time if needed.
  684. or eax, CR4_PGE
  685. mov cr4, eax
  686. ktb_eb: stdRET _KeFlushCurrentTb
  687. stdENDP _KeFlushCurrentTb
  688. ;;
  689. ;; moved KiFlushDcache below KeFlushCurrentTb for BBT purposes. BBT
  690. ;; needs an end label to treat KeFlushCurrentTb as data and to keep together.
  691. ;;
  692. page , 132
  693. subttl "Flush Data Cache"
  694. ;++
  695. ;
  696. ; VOID
  697. ; KiFlushDcache (
  698. ; )
  699. ;
  700. ; VOID
  701. ; KiFlushIcache (
  702. ; )
  703. ;
  704. ; Routine Description:
  705. ;
  706. ; This routine does nothing on i386 and i486 systems. Why? Because
  707. ; (a) their caches are completely transparent, (b) they don't have
  708. ; instructions to flush their caches.
  709. ;
  710. ; Arguments:
  711. ;
  712. ; None.
  713. ;
  714. ; Return Value:
  715. ;
  716. ; None.
  717. ;
  718. ;--
  719. cPublicProc _KiFlushDcache ,0
  720. cPublicProc _KiFlushIcache ,0
  721. stdRET _KiFlushIcache
  722. stdENDP _KiFlushIcache
  723. stdENDP _KiFlushDcache
  724. _TEXT$00 ends
  725. INIT SEGMENT DWORD PUBLIC 'CODE'
  726. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  727. ;++
  728. ;
  729. ; VOID
  730. ; Ki386EnableGlobalPage (
  731. ; IN volatile PLONG Number
  732. ; )
  733. ;
  734. ; /*++
  735. ;
  736. ; Routine Description:
  737. ;
  738. ; This routine enables the global page PDE/PTE support in the system,
  739. ; and stalls until complete and them sets the current processor's cr4
  740. ; register to enable global page support.
  741. ;
  742. ; Arguments:
  743. ;
  744. ; Number - Supplies a pointer to the count of the number of processors in
  745. ; the configuration.
  746. ;
  747. ; Return Value:
  748. ;
  749. ; None.
  750. ;--
  751. cPublicProc _Ki386EnableGlobalPage,1
  752. push esi
  753. push edi
  754. push ebx
  755. mov edx, [esp+16] ; pointer to Number
  756. pushfd
  757. cli
  758. ;
  759. ; Wait for all processors
  760. ;
  761. lock dec dword ptr [edx] ; count down
  762. egp10: YIELD
  763. cmp dword ptr [edx], 0 ; wait for all processors to signal
  764. jnz short egp10
  765. cmp byte ptr PCR[PcNumber], 0 ; processor 0?
  766. jne short egp20
  767. ;
  768. ; Install proper KeFlushCurrentTb function.
  769. ;
  770. mov edi, ktb00
  771. mov esi, ktb_gb
  772. mov ecx, ktb_eb - ktb_gb + 1
  773. rep movsb
  774. mov byte ptr [ktb_eb], 0
  775. ;
  776. ; Wait for P0 to signal that proper flush TB handlers have been installed
  777. ;
  778. egp20: cmp byte ptr [ktb_eb], 0
  779. jnz short egp20
  780. ;
  781. ; Flush TB, and enable global page support
  782. ; (note load of CR4 is explicitly done before the load of CR3
  783. ; to work around P6 step B0 errata 11)
  784. ;
  785. mov eax, cr4
  786. and eax, not CR4_PGE ; should not be set, but let's be safe
  787. mov ecx, cr3
  788. mov cr4, eax
  789. mov cr3, ecx ; Flush TB
  790. or eax, CR4_PGE ; enable global TBs
  791. mov cr4, eax
  792. popfd
  793. pop ebx
  794. pop edi
  795. pop esi
  796. stdRET _Ki386EnableGlobalPage
  797. stdENDP _Ki386EnableGlobalPage
  798. ;++
  799. ;
  800. ; VOID
  801. ; Ki386EnableDE (
  802. ; IN volatile PLONG Number
  803. ; )
  804. ;
  805. ; /*++
  806. ;
  807. ; Routine Description:
  808. ;
  809. ; This routine sets DE bit in CR4 to enable IO breakpoints
  810. ;
  811. ; Arguments:
  812. ;
  813. ; Number - Supplies a pointer to the count of the number of processors in
  814. ; the configuration.
  815. ;
  816. ; Return Value:
  817. ;
  818. ; None.
  819. ;--
  820. cPublicProc _Ki386EnableDE,1
  821. mov eax, cr4
  822. or eax, CR4_DE
  823. mov cr4, eax
  824. stdRET _Ki386EnableDE
  825. stdENDP _Ki386EnableDE
  826. ;++
  827. ;
  828. ; VOID
  829. ; Ki386EnableFxsr (
  830. ; IN volatile PLONG Number
  831. ; )
  832. ;
  833. ; /*++
  834. ;
  835. ; Routine Description:
  836. ;
  837. ; This routine sets OSFXSR bit in CR4 to indicate that OS supports
  838. ; FXSAVE/FXRSTOR for use during context switches
  839. ;
  840. ; Arguments:
  841. ;
  842. ; Number - Supplies a pointer to the count of the number of processors in
  843. ; the configuration.
  844. ;
  845. ; Return Value:
  846. ;
  847. ; None.
  848. ;--
  849. cPublicProc _Ki386EnableFxsr,1
  850. mov eax, cr4
  851. or eax, CR4_FXSR
  852. mov cr4, eax
  853. stdRET _Ki386EnableFxsr
  854. stdENDP _Ki386EnableFxsr
  855. ;++
  856. ;
  857. ; VOID
  858. ; Ki386EnableXMMIExceptions (
  859. ; IN volatile PLONG Number
  860. ; )
  861. ;
  862. ; /*++
  863. ;
  864. ; Routine Description:
  865. ;
  866. ; This routine installs int 19 XMMI unmasked Numeric Exception handler
  867. ; and sets OSXMMEXCPT bit in CR4 to indicate that OS supports
  868. ; unmasked Katmai New Instruction technology exceptions.
  869. ;
  870. ; Arguments:
  871. ;
  872. ; Number - Supplies a pointer to count of the number of processors in
  873. ; the configuration.
  874. ;
  875. ; Return Value:
  876. ;
  877. ; None.
  878. ;--
  879. cPublicProc _Ki386EnableXMMIExceptions,1
  880. ;Set up IDT for INT19
  881. mov ecx,PCR[PcIdt] ;Get IDT address
  882. lea eax, [ecx] + 098h ;XMMI exception is int 19
  883. mov byte ptr [eax + 5], 08eh ;P=1,DPL=0,Type=e
  884. mov word ptr [eax + 2], KGDT_R0_CODE ;Kernel code selector
  885. mov edx, offset FLAT:_KiTrap13 ;Address of int 19 handler
  886. mov ecx,edx
  887. mov word ptr [eax],cx ;addr moves into low byte
  888. shr ecx,16
  889. mov word ptr [eax + 6],cx ;addr moves into high byte
  890. ;Enable XMMI exception handling
  891. mov eax, cr4
  892. or eax, CR4_XMMEXCPT
  893. mov cr4, eax
  894. stdRET _Ki386EnableXMMIExceptions
  895. stdENDP _Ki386EnableXMMIExceptions
  896. ;++
  897. ;
  898. ; VOID
  899. ; Ki386EnableCurrentLargePage (
  900. ; IN ULONG IdentityAddr,
  901. ; IN ULONG IdentityCr3
  902. ; )
  903. ;
  904. ; /*++
  905. ;
  906. ; Routine Description:
  907. ;
  908. ; This routine enables the large page PDE support in the processor.
  909. ;
  910. ; Arguments:
  911. ;
  912. ; IdentityAddr - Supplies the linear address of the beginning of this
  913. ; function where (linear == physical).
  914. ;
  915. ; IdentityCr3 - Supplies a pointer to the temporary page directory and
  916. ; page tables that provide both the kernel (virtual ->physical) and
  917. ; identity (linear->physical) mappings needed for this function.
  918. ;
  919. ; Return Value:
  920. ;
  921. ; None.
  922. ;--
  923. public _Ki386EnableCurrentLargePageEnd
  924. cPublicProc _Ki386EnableCurrentLargePage,2
  925. mov ecx,[esp]+4 ; (ecx)-> IdentityAddr
  926. mov edx,[esp]+8 ; (edx)-> IdentityCr3
  927. pushfd ; save current IF state
  928. cli ; disable interrupts
  929. mov eax, cr3 ; (eax)-> original Cr3
  930. mov cr3, edx ; load Cr3 with Identity mapping
  931. sub ecx, offset _Ki386EnableCurrentLargePage
  932. add ecx, offset _Ki386LargePageIdentityLabel
  933. jmp ecx ; jump to (linear == physical)
  934. _Ki386LargePageIdentityLabel:
  935. mov ecx, cr0
  936. and ecx, NOT CR0_PG ; clear PG bit to disable paging
  937. mov cr0, ecx ; disable paging
  938. jmp $+2
  939. mov edx, cr4
  940. or edx, CR4_PSE ; enable Page Size Extensions
  941. mov cr4, edx
  942. mov edx, offset OriginalMapping
  943. or ecx, CR0_PG ; set PG bit to enable paging
  944. mov cr0, ecx ; enable paging
  945. jmp edx ; Return to original mapping.
  946. OriginalMapping:
  947. mov cr3, eax ; restore original Cr3
  948. popfd ; restore interrupts to previous
  949. stdRET _Ki386EnableCurrentLargePage
  950. _Ki386EnableCurrentLargePageEnd:
  951. stdENDP _Ki386EnableCurrentLargePage
  952. INIT ends
  953. _TEXT$00 SEGMENT PARA PUBLIC 'CODE'
  954. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  955. page , 132
  956. subttl "Swap Process"
  957. ;++
  958. ;
  959. ; VOID
  960. ; KiSwapProcess (
  961. ; IN PKPROCESS NewProcess,
  962. ; IN PKPROCESS OldProcess
  963. ; )
  964. ;
  965. ; Routine Description:
  966. ;
  967. ; This function swaps the address space to another process by flushing
  968. ; the data cache, the instruction cache, the translation buffer, and
  969. ; establishes a new directory table base.
  970. ;
  971. ; It also swaps in the LDT and IOPM of the new process. This is necessary
  972. ; to avoid bogus mismatches in SwapContext.
  973. ;
  974. ; NOTE: keep in sync with process switch part of SwapContext
  975. ;
  976. ; Arguments:
  977. ;
  978. ; Process - Supplies a pointer to a control object of type process.
  979. ;
  980. ; Return Value:
  981. ;
  982. ; None.
  983. ;
  984. ;--
  985. cPublicProc _KiSwapProcess ,2
  986. cPublicFpo 2, 0
  987. mov edx,[esp]+4 ; (edx)-> New process
  988. mov eax,[esp]+8 ; (eax)-> Old Process
  989. ;
  990. ; Set the processor number in the new process and clear it in the old.
  991. ;
  992. ifndef NT_UP
  993. mov ecx, PCR[PcSetMember]
  994. lock xor [edx]+PrActiveProcessors,ecx ; set bit in new processor set
  995. lock xor [eax]+PrActiveProcessors,ecx ; clear bit in old processor set
  996. if DBG
  997. test [edx]+PrActiveProcessors,ecx ; test if bit set in new set
  998. jz kisp_error1 ; if z, bit not set in new set
  999. test [eax]+PrActiveProcessors,ecx ; test if bit clear in old set
  1000. jnz kisp_error ; if nz, bit not clear in old set
  1001. endif
  1002. endif
  1003. ;
  1004. ; Change LDT, If either the source or target process has an LDT we need to
  1005. ; load the new one.
  1006. ;
  1007. mov ecx, [edx]+PrLdtDescriptor
  1008. or ecx, [eax]+PrLdtDescriptor
  1009. jnz kisp_load_ldt ; if nz, LDT limit
  1010. kisp_load_ldt_ret: ; if nz, LDT limit
  1011. ;
  1012. ; Load the new CR3 and as a side effect flush non-global TB entries.
  1013. ;
  1014. mov eax,[edx]+PrDirectoryTableBase
  1015. mov cr3,eax
  1016. mov ecx,PCR[PcTssCopy] ; (ecx)-> TSS
  1017. ;
  1018. ; Clear gs so it can't leak across processes
  1019. ;
  1020. xor eax,eax ; assume ldtr is to be NULL
  1021. mov gs,ax ; Clear gs. (also workarounds
  1022. ;
  1023. ; Change IOPM
  1024. ;
  1025. mov ax,[edx]+PrIopmOffset
  1026. mov [ecx]+TssIoMapBase,ax
  1027. stdRET _KiSwapProcess
  1028. kisp_load_ldt:
  1029. ;
  1030. ; Edit LDT descriptor
  1031. ;
  1032. mov eax,[edx+PrLdtDescriptor]
  1033. test eax, eax
  1034. je @f
  1035. mov ecx,PCR[PcGdt]
  1036. mov [ecx+KGDT_LDT],eax
  1037. mov eax,[edx+PrLdtDescriptor+4]
  1038. mov [ecx+KGDT_LDT+4],eax
  1039. ;
  1040. ; Set up int 21 descriptor of IDT. If the process does not have Ldt, it
  1041. ; should never make any int 21 call. If it does, an exception is generated.
  1042. ; If the process has Ldt, we need to update int21 entry of LDT for the process.
  1043. ; Note the Int21Descriptor of the process may simply indicate an invalid
  1044. ; entry. In which case, the int 21 will be trapped to the kernel.
  1045. ;
  1046. mov ecx, PCR[PcIdt]
  1047. mov eax, [edx+PrInt21Descriptor]
  1048. mov [ecx+21h*8], eax
  1049. mov eax, [edx+PrInt21Descriptor+4]
  1050. mov [ecx+21h*8+4], eax
  1051. mov eax,KGDT_LDT ;@@32-bit op to avoid prefix
  1052. @@: lldt ax
  1053. jmp kisp_load_ldt_ret
  1054. if DBG
  1055. kisp_error1: int 3
  1056. kisp_error: int 3
  1057. endif
  1058. stdENDP _KiSwapProcess
  1059. page ,132
  1060. subttl "Idle Loop"
  1061. ;++
  1062. ;
  1063. ; VOID
  1064. ; KiIdleLoop(
  1065. ; VOID
  1066. ; )
  1067. ;
  1068. ; Routine Description:
  1069. ;
  1070. ; This routine continuously executes the idle loop and never returns.
  1071. ;
  1072. ; Arguments:
  1073. ;
  1074. ; ebx - Address of the current processor's PCR.
  1075. ;
  1076. ; Return value:
  1077. ;
  1078. ; None - routine never returns.
  1079. ;
  1080. ;--
  1081. cPublicFastCall KiIdleLoop ,0
  1082. cPublicFpo 0, 0
  1083. if DBG
  1084. xor edi, edi ; reset poll breakin counter
  1085. endif
  1086. jmp short kid20 ; Skip HalIdleProcessor on first iteration
  1087. ;
  1088. ; There are no entries in the DPC list and a thread has not been selected
  1089. ; for execution on this processor. Call the HAL so power managment can be
  1090. ; performed.
  1091. ;
  1092. ; N.B. The HAL is called with interrupts disabled. The HAL will return
  1093. ; with interrupts enabled.
  1094. ;
  1095. ; N.B. Use a call instruction instead of a push-jmp, as the call instruction
  1096. ; executes faster and won't invalidate the processor's call-return stack
  1097. ; cache.
  1098. ;
  1099. kid10: lea ecx, [ebx].PcPrcbData.PbPowerState
  1100. call dword ptr [ecx].PpIdleFunction ; (ecx) = Arg0
  1101. ;
  1102. ; Give the debugger an opportunity to gain control on debug systems.
  1103. ;
  1104. ; N.B. On an MP system the lowest numbered idle processor is the only
  1105. ; processor that polls for a breakin request.
  1106. ;
  1107. kid20:
  1108. if DBG
  1109. ifndef NT_UP
  1110. mov eax, _KiIdleSummary ; get idle summary
  1111. mov ecx, [ebx].PcSetMember ; get set member
  1112. dec ecx ; compute right bit mask
  1113. and eax, ecx ; check if any lower bits set
  1114. jnz short CheckDpcList ; if nz, not lowest numbered
  1115. endif
  1116. dec edi ; decrement poll counter
  1117. jg short CheckDpcList ; if g, not time to poll
  1118. POLL_DEBUGGER ; check if break in requested
  1119. endif
  1120. kid30:
  1121. if DBG
  1122. ifndef NT_UP
  1123. mov edi, 20 * 1000 ; set breakin poll interval
  1124. else
  1125. mov edi, 100 ; UP idle loop has a HLT in it
  1126. endif
  1127. endif
  1128. CheckDpcList0: ;
  1129. YIELD
  1130. ;
  1131. ; Disable interrupts and check if there is any work in the DPC list of the
  1132. ; current processor or a target processor.
  1133. ;
  1134. CheckDpcList:
  1135. ;
  1136. ; N.B. The following code enables interrupts for a few cycles, then
  1137. ; disables them again for the subsequent DPC and next thread
  1138. ; checks.
  1139. ;
  1140. sti ; enable interrupts
  1141. nop ;
  1142. nop ;
  1143. cli ; disable interrupts
  1144. ;
  1145. ; Process the deferred procedure call list for the current processor.
  1146. ;
  1147. mov eax, [ebx]+PcPrcbData+PbDpcQueueDepth ; get DPC queue depth
  1148. or eax, [ebx]+PcPrcbData+PbTimerRequest ; merge timer request
  1149. ifndef NT_UP
  1150. or eax, [ebx]+PcPrcbData+PbDeferredReadyListHead ; merge deferred list head
  1151. endif
  1152. jz short CheckNextThread ; if z, no DPC's or timers to process
  1153. mov cl, DISPATCH_LEVEL ; set interrupt level
  1154. fstCall HalClearSoftwareInterrupt ; clear software interrupt
  1155. lea ecx, [ebx].PcPrcbData ; set current PRCB address
  1156. CAPSTART <@KiIdleLoop@0,@KiRetireDpcList@4>
  1157. fstCall KiRetireDpcList ; process the current DPC list
  1158. CAPEND <@KiIdleLoop@0>
  1159. if DBG
  1160. xor edi, edi ; clear breakin poll interval
  1161. endif
  1162. ;
  1163. ; Check if a thread has been selected to run on the current processor.
  1164. ;
  1165. CheckNextThread: ;
  1166. cmp dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; thread selected?
  1167. ifdef NT_UP
  1168. je short kid10 ; if eq, no thread selected
  1169. else
  1170. je kid40 ; if eq, no thread selected.
  1171. endif
  1172. ;
  1173. ; Raise IRQL to synchronization level and enable interrupts.
  1174. ;
  1175. ifndef NT_UP
  1176. RaiseIrql SYNCH_LEVEL, NoOld ; raise IRQL to synchronizaiton level
  1177. endif
  1178. sti ; enable interrupts
  1179. mov edi, [ebx].PcPrcbData.PbCurrentThread ; get idle thread address
  1180. ;
  1181. ; Set context swap busy for idle thread and acquire the PRCB lock.
  1182. ;
  1183. ifndef NT_UP
  1184. mov byte ptr [edi].ThSwapBusy, 1 ; set context swap busy
  1185. lock bts dword ptr [ebx].PcPrcbData.PbPrcbLock, 0 ; try to acquire PRCB Lock
  1186. jnc short kid33 ; if nc, PRCB lock acquired
  1187. lea ecx, [ebx].PcPrcbData.PbPrcbLock ; get PRCB lock address
  1188. fstCall KefAcquireSpinLockAtDpcLevel ; acquire current PRCB lock
  1189. endif
  1190. ;
  1191. ; If a thread had been scheduled for this processor but was removed from
  1192. ; eligibility (e.g., an affinity change), then the new thread could be the
  1193. ; idle thread.
  1194. ;
  1195. kid33: mov esi, [ebx].PcPrcbData.PbNextThread ; get next thread address
  1196. ifndef NT_UP
  1197. cmp esi, edi ; check if idle thread
  1198. je short kisame ; if e, processor idle again
  1199. endif
  1200. and dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; clear next thread
  1201. mov [ebx].PcPrcbData.PbCurrentThread, esi ; set new thread address
  1202. mov byte ptr [esi]+ThState, Running ; set thread state running
  1203. ;
  1204. ; Clear idle schedule since a new thread has been selected for execution on
  1205. ; this processor and release the PRCB lock.
  1206. ;
  1207. ifndef NT_UP
  1208. and byte ptr [ebx].PcPrcbData.PbIdleSchedule, 0 ; clear idle schedule
  1209. and dword ptr [ebx].PcPrcbData.PbPrcbLock, 0 ; release current PRCB lock
  1210. endif
  1211. kid35: ;
  1212. CAPSTART <@KiIdleLoop@0,SwapContext>
  1213. mov ecx, APC_LEVEL ; set APC bypass disable
  1214. call SwapContext ; swap context
  1215. CAPEND <@KiIdleLoop@0>
  1216. ifndef NT_UP
  1217. LowerIrql DISPATCH_LEVEL ; lower IRQL to dispatch level
  1218. endif
  1219. jmp kid30 ;
  1220. ;
  1221. ; The new thread is the Idle thread (same as old thread). This can happen
  1222. ; rarely when a thread scheduled for this processor is made unable to run
  1223. ; on this processor. As this processor has again been marked idle, other
  1224. ; processors may unconditionally assign new threads to this processor.
  1225. ;
  1226. ifndef NT_UP
  1227. kisame: and dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; clear next thread
  1228. and dword ptr [ebx].PcPrcbData.PbPrcbLock, 0 ; release current PRCB lock
  1229. and byte ptr [edi].ThSwapBusy, 0 ; set idle thread context swap idle
  1230. jmp kid30 ;
  1231. ;
  1232. ; Call idle schedule if requested.
  1233. ;
  1234. kid40: cmp byte ptr [ebx].PcPrcbData.PbIdleSchedule, 0 ; check if idle schedule
  1235. je kid10 ; if e, idle schedule not requested
  1236. sti ; enable interrupts
  1237. lea ecx, [ebx].PcPrcbData ; get current PRCB address
  1238. fstCall KiIdleSchedule ; attempt to schedule thread
  1239. test eax, eax ; test if new thread schedule
  1240. mov esi, eax ; set new thread address
  1241. mov edi, [ebx].PcPrcbData.PbIdleThread ; get idle thread address
  1242. jnz short kid35 ; if nz, new thread scheduled
  1243. jmp kid30 ;
  1244. endif
  1245. fstENDP KiIdleLoop
  1246. ifdef DBGMP
  1247. cPublicProc _KiPollDebugger,0
  1248. cPublicFpo 0,3
  1249. push eax
  1250. push ecx
  1251. push edx
  1252. POLL_DEBUGGER
  1253. pop edx
  1254. pop ecx
  1255. pop eax
  1256. stdRET _KiPollDebugger
  1257. stdENDP _KiPollDebugger
  1258. endif
  1259. page , 132
  1260. subttl "Adjust TSS ESP0 value"
  1261. ;++
  1262. ;
  1263. ; VOID
  1264. ; KiAdjustEsp0 (
  1265. ; IN PKTRAP_FRAME TrapFrame
  1266. ; )
  1267. ;
  1268. ; Routine Description:
  1269. ;
  1270. ; This routine puts the apropriate ESP0 value in the esp0 field of the
  1271. ; TSS. This allows protect mode and V86 mode to use the same stack
  1272. ; frame. The ESP0 value for protected mode is 16 bytes lower than
  1273. ; for V86 mode to compensate for the missing segment registers.
  1274. ;
  1275. ; Arguments:
  1276. ;
  1277. ; TrapFrame - Supplies a pointer to the TrapFrame.
  1278. ;
  1279. ; Return Value:
  1280. ;
  1281. ; None.
  1282. ;
  1283. ;--
  1284. cPublicProc _Ki386AdjustEsp0 ,1
  1285. if DBG
  1286. ;
  1287. ; Make sure we are not called when the trap frame can be
  1288. ; edited by a SetContextThread.
  1289. ;
  1290. CurrentIrql
  1291. cmp al, APC_LEVEL
  1292. jge @f
  1293. int 3
  1294. @@:
  1295. endif
  1296. mov eax, PCR[PcPrcbData.PbCurrentThread] ; get current thread address
  1297. mov edx, [esp + 4] ; edx -> trap frame
  1298. mov eax, [eax]+ThInitialStack ; eax = base of stack
  1299. test dword ptr [edx]+TsEFlags, EFLAGS_V86_MASK ; is this a V86 frame?
  1300. jnz short ae10 ; if nz, V86 frame
  1301. sub eax, TsV86Gs - TsHardwareSegSS ; compensate for missing regs
  1302. ae10: sub eax, NPX_FRAME_LENGTH ;
  1303. pushfd ; Make sure we don't move
  1304. cli ; processors while we do this
  1305. mov edx, PCR[PcTssCopy] ;
  1306. mov [edx]+TssEsp0, eax ; set Esp0 value
  1307. popfd ;
  1308. stdRET _Ki386AdjustEsp0
  1309. stdENDP _Ki386AdjustEsp0
  1310. _TEXT$00 ends
  1311. end