Source code of Windows XP (NT5)
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.

2195 lines
63 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. FPOFRAME macro a, b
  36. .FPO ( a, b, 0, 0, 0, 0 )
  37. endm
  38. .list
  39. EXTRNP KeAcquireQueuedSpinLockAtDpcLevel,1,,FASTCALL
  40. EXTRNP KeReleaseQueuedSpinLockFromDpcLevel,1,,FASTCALL
  41. EXTRNP KeTryToAcquireQueuedSpinLockAtRaisedIrql,1,,FASTCALL
  42. EXTRNP KeAcquireQueuedSpinLockRaiseToSynch,1,,FASTCALL
  43. EXTRNP KfAcquireSpinLock,1,IMPORT,FASTCALL
  44. EXTRNP HalClearSoftwareInterrupt,1,IMPORT,FASTCALL
  45. EXTRNP HalRequestSoftwareInterrupt,1,IMPORT,FASTCALL
  46. EXTRNP KiActivateWaiterQueue,1,,FASTCALL
  47. EXTRNP KiReadyThread,1,,FASTCALL
  48. EXTRNP KiWaitTest,2,,FASTCALL
  49. EXTRNP KfLowerIrql,1,IMPORT,FASTCALL
  50. EXTRNP KfRaiseIrql,1,IMPORT,FASTCALL
  51. EXTRNP _KeGetCurrentIrql,0,IMPORT
  52. EXTRNP ___KeGetCurrentThread,0
  53. EXTRNP _KiDeliverApc,3
  54. EXTRNP _KiQuantumEnd,0
  55. EXTRNP _KeBugCheckEx,5
  56. EXTRNP _KeBugCheck,1
  57. extrn _KiTrap13:PROC
  58. extrn _KeI386FxsrPresent:BYTE
  59. extrn _KiDispatcherLock:DWORD
  60. extrn _KeFeatureBits:DWORD
  61. extrn _KeThreadSwitchCounters:DWORD
  62. extrn __imp_@KfLowerIrql@4:DWORD
  63. extrn _KiDispatcherReadyListHead:DWORD
  64. extrn _KiIdleSummary:DWORD
  65. extrn _KiIdleSMTSummary:DWORD
  66. extrn _KiReadySummary:DWORD
  67. extrn _PPerfGlobalGroupMask:DWORD
  68. EXTRNP WmiTraceContextSwap,2,,FASTCALL
  69. EXTRNP PerfInfoLogDpc,3,,FASTCALL
  70. if DBG
  71. extrn _KdDebuggerEnabled:BYTE
  72. EXTRNP _DbgBreakPoint,0
  73. EXTRNP _KdPollBreakIn,0
  74. extrn _DbgPrint:near
  75. extrn _MsgDpcTrashedEsp:BYTE
  76. extrn _MsgDpcTimeout:BYTE
  77. extrn _KiDPCTimeout:DWORD
  78. endif
  79. _TEXT$00 SEGMENT PARA PUBLIC 'CODE'
  80. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  81. cPublicFastCall KiRDTSC, 1
  82. rdtsc ; read the timestamp counter
  83. mov [ecx], eax ; return the low 32 bits
  84. mov [ecx+4], edx ; return the high 32 bits
  85. fstRET KiRDTSC
  86. fstENDP KiRDTSC
  87. page ,132
  88. subttl "Unlock Dispatcher Database"
  89. ;++
  90. ;
  91. ; VOID
  92. ; KiUnlockDispatcherDatabase (
  93. ; IN KIRQL OldIrql
  94. ; )
  95. ;
  96. ; Routine Description:
  97. ;
  98. ; This routine is entered at IRQL DISPATCH_LEVEL with the dispatcher
  99. ; database locked. Its function is to either unlock the dispatcher
  100. ; database and return or initiate a context switch if another thread
  101. ; has been selected for execution.
  102. ;
  103. ; Arguments:
  104. ;
  105. ; (TOS) Return address
  106. ;
  107. ; (ecx) OldIrql - Supplies the IRQL when the dispatcher database
  108. ; lock was acquired.
  109. ;
  110. ; Return Value:
  111. ;
  112. ; None.
  113. ;
  114. ;--
  115. cPublicFastCall KiUnlockDispatcherDatabase, 1
  116. ;
  117. ; Check if a new thread is scheduled for execution.
  118. ;
  119. cmp PCR[PcPrcbData+PbNextThread], 0 ; check if next thread
  120. jne short Kiu20 ; if ne, new thread scheduled
  121. ;
  122. ; Release dispatcher database lock, lower IRQL to its previous level,
  123. ; and return.
  124. ;
  125. Kiu00: ;
  126. ifndef NT_UP
  127. mov eax, PCR[PcPrcb] ; get address of PRCB
  128. push ecx ; save IRQL for lower IRQL
  129. lea ecx, [eax]+PbLockQueue+(8*LockQueueDispatcherLock)
  130. fstCall KeReleaseQueuedSpinLockFromDpcLevel
  131. pop ecx ; get OldIrql
  132. endif
  133. ;
  134. ; N.B. This exit jumps directly to the lower IRQL routine which has a
  135. ; compatible fastcall interface.
  136. ;
  137. jmp dword ptr [__imp_@KfLowerIrql@4] ; lower IRQL to previous level
  138. ;
  139. ; A new thread has been selected to run on the current processor, but
  140. ; the new IRQL is not below dispatch level. If the current processor is
  141. ; not executing a DPC, then request a dispatch interrupt on the current
  142. ; processor.
  143. ;
  144. Kiu10: cmp dword ptr PCR[PcPrcbData.PbDpcRoutineActive],0 ; check if DPC routine active
  145. jne short Kiu00 ; if ne, DPC routine is active
  146. push ecx ; save new IRQL
  147. ifndef NT_UP
  148. mov eax, PCR[PcPrcb] ; get address of PRCB
  149. lea ecx, [eax]+PbLockQueue+(8*LockQueueDispatcherLock)
  150. fstCall KeReleaseQueuedSpinLockFromDpcLevel
  151. endif
  152. mov cl, DISPATCH_LEVEL ; request dispatch interrupt
  153. fstCall HalRequestSoftwareInterrupt ;
  154. pop ecx ; restore new IRQL
  155. ;
  156. ; N.B. This exit jumps directly to the lower IRQL routine which has a
  157. ; compatible fastcall interface.
  158. ;
  159. jmp dword ptr [__imp_@KfLowerIrql@4] ; lower IRQL to previous level
  160. ;
  161. ; Check if the previous IRQL is less than dispatch level.
  162. ;
  163. Kiu20: cmp cl, DISPATCH_LEVEL ; check if IRQL below dispatch level
  164. jge short Kiu10 ; if ge, not below dispatch level
  165. ;
  166. ; There is a new thread scheduled for execution and the previous IRQL is
  167. ; less than dispatch level. Context switch to the new thread immediately.
  168. ;
  169. ;
  170. ; N.B. The following registers MUST be saved such that ebp is saved last.
  171. ; This is done so the debugger can find the saved ebp for a thread
  172. ; that is not currently in the running state.
  173. ;
  174. .fpo (0, 0, 0, 4, 1, 0)
  175. sub esp, 4*4
  176. mov [esp+12], ebx ; save registers
  177. mov [esp+8], esi ;
  178. mov [esp+4], edi ;
  179. mov [esp+0], ebp ;
  180. mov ebx, PCR[PcSelfPcr] ; get address of PCR
  181. mov esi, [ebx].PcPrcbData.PbNextThread ; get next thread address
  182. mov edi, [ebx].PcPrcbData.PbCurrentThread ; get current thread address
  183. mov dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; clear next thread address
  184. mov [ebx].PcPrcbData.PbCurrentThread, esi ; set current thread address
  185. mov [edi].ThWaitIrql, cl ; save previous IRQL
  186. mov ecx, edi ; set address of current thread
  187. mov byte ptr [edi].ThIdleSwapBlock, 1
  188. fstCall KiReadyThread ; reready thread for execution
  189. mov cl, [edi].ThWaitIrql ; set APC interrupt bypass disable
  190. CAPSTART <@KiUnlockDispatcherDatabase@4,SwapContext>
  191. call SwapContext ; swap context
  192. CAPEND <@KiUnlockDispatcherDatabase@4>
  193. or al, al ; check if kernel APC pending
  194. mov cl, [esi].ThWaitIrql ; get original wait IRQL
  195. jnz short Kiu50 ; if nz, kernel APC pending
  196. Kiu30: mov ebp, [esp+0] ; restore registers
  197. mov edi, [esp+4] ;
  198. mov esi, [esp+8] ;
  199. mov ebx, [esp+12] ;
  200. add esp, 4*4
  201. ;
  202. ; N.B. This exit jumps directly to the lower IRQL routine which has a
  203. ; compatible fastcall interface.
  204. ;
  205. jmp dword ptr [__imp_@KfLowerIrql@4] ; lower IRQL to previous level
  206. Kiu50: mov cl, APC_LEVEL ; lower IRQL to APC level
  207. fstCall KfLowerIrql ;
  208. xor eax, eax ; set previous mode to kernel
  209. CAPSTART <@KiUnlockDispatcherDatabase@4,_KiDeliverApc@12>
  210. stdCall _KiDeliverApc, <eax, eax, eax> ; deliver kernel mode APC
  211. CAPEND <@KiUnlockDispatcherDatabase@4>
  212. xor ecx, ecx ; set original wait IRQL
  213. jmp short Kiu30
  214. fstENDP KiUnlockDispatcherDatabase
  215. page ,132
  216. subttl "Swap Context"
  217. ;++
  218. ;
  219. ; BOOLEAN
  220. ; KiSwapContext (
  221. ; IN PKTHREAD Thread
  222. ; )
  223. ;
  224. ; Routine Description:
  225. ;
  226. ; This function is a small wrapper, callable from C code, that marshalls
  227. ; arguments and calls the actual swap context routine.
  228. ;
  229. ; Arguments:
  230. ;
  231. ; Thread (ecx) - Supplies the address of the new thread.
  232. ;
  233. ; Return Value:
  234. ;
  235. ; If a kernel APC is pending, then a value of TRUE is returned. Otherwise,
  236. ; a value of FALSE is returned.
  237. ;
  238. ;--
  239. cPublicFastCall KiSwapContext, 1
  240. .fpo (0, 0, 0, 4, 1, 0)
  241. ;
  242. ; N.B. The following registers MUST be saved such that ebp is saved last.
  243. ; This is done so the debugger can find the saved ebp for a thread
  244. ; that is not currently in the running state.
  245. ;
  246. sub esp, 4*4
  247. mov [esp+12], ebx ; save registers
  248. mov [esp+8], esi ;
  249. mov [esp+4], edi ;
  250. mov [esp+0], ebp ;
  251. mov ebx, PCR[PcSelfPcr] ; set address of PCR
  252. mov esi, ecx ; set next thread address
  253. mov edi, [ebx].PcPrcbData.PbCurrentThread ; get current thread address
  254. mov [ebx].PcPrcbData.PbCurrentThread, esi ; set current thread address
  255. mov cl, [edi].ThWaitirql ; set APC interrupt bypass disable
  256. call SwapContext ; swap context
  257. mov ebp, [esp+0] ; restore registers
  258. mov edi, [esp+4] ;
  259. mov esi, [esp+8] ;
  260. mov ebx, [esp+12] ;
  261. add esp, 4*4 ;
  262. fstRET KiSwapContext ;
  263. fstENDP KiSwapContext
  264. page ,132
  265. subttl "Dispatch Interrupt"
  266. ;++
  267. ;
  268. ; Routine Description:
  269. ;
  270. ; This routine is entered as the result of a software interrupt generated
  271. ; at DISPATCH_LEVEL. Its function is to process the Deferred Procedure Call
  272. ; (DPC) list, and then perform a context switch if a new thread has been
  273. ; selected for execution on the processor.
  274. ;
  275. ; This routine is entered at IRQL DISPATCH_LEVEL with the dispatcher
  276. ; database unlocked. When a return to the caller finally occurs, the
  277. ; IRQL remains at DISPATCH_LEVEL, and the dispatcher database is still
  278. ; unlocked.
  279. ;
  280. ; Arguments:
  281. ;
  282. ; None
  283. ;
  284. ; Return Value:
  285. ;
  286. ; None.
  287. ;
  288. ;--
  289. align 16
  290. cPublicProc _KiDispatchInterrupt ,0
  291. cPublicFpo 0, 0
  292. mov ebx, PCR[PcSelfPcr] ; get address of PCR
  293. kdi00: lea eax, [ebx].PcPrcbData.PbDpcListHead ; get DPC listhead address
  294. ;
  295. ; Disable interrupts and check if there is any work in the DPC list
  296. ; of the current processor.
  297. ;
  298. kdi10: cli ; disable interrupts
  299. cmp eax, [eax].LsFlink ; check if DPC List is empty
  300. je short kdi40 ; if eq, list is empty
  301. push ebp ; save register
  302. ;
  303. ; Exceptions occuring in DPCs are unrelated to any exception handlers
  304. ; in the interrupted thread. Terminate the exception list.
  305. ;
  306. push [ebx].PcExceptionList
  307. mov [ebx].PcExceptionList, EXCEPTION_CHAIN_END
  308. ;
  309. ; Switch to the DPC stack for this processor.
  310. ;
  311. mov edx, esp
  312. mov esp, [ebx].PcPrcbData.PbDpcStack
  313. push edx
  314. .fpo (0, 0, 0, 1, 1, 0)
  315. mov ebp, eax ; set address of DPC listhead
  316. CAPSTART <_KiDispatchInterrupt,KiRetireDpcList>
  317. call KiRetireDpcList ; process the current DPC list
  318. CAPEND <_KiDispatchInterrupt>
  319. ;
  320. ; Switch back to the current thread stack, restore the exception list
  321. ; and saved EBP.
  322. ;
  323. pop esp
  324. pop [ebx].PcExceptionList
  325. pop ebp
  326. .fpo (0, 0, 0, 0, 0, 0)
  327. ;
  328. ; Check to determine if quantum end is requested.
  329. ;
  330. ; N.B. If a new thread is selected as a result of processing the quantum
  331. ; end request, then the new thread is returned with the dispatcher
  332. ; database locked. Otherwise, NULL is returned with the dispatcher
  333. ; database unlocked.
  334. ;
  335. kdi40: sti ; enable interrupts
  336. cmp dword ptr [ebx].PcPrcbData.PbQuantumEnd, 0 ; quantum end requested
  337. jne kdi90 ; if neq, quantum end request
  338. ;
  339. ; Check to determine if a new thread has been selected for execution on this
  340. ; processor.
  341. ;
  342. cmp dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; check addr of next thread object
  343. je kdi70 ; if eq, then no new thread
  344. ;
  345. ; Disable interrupts and attempt to acquire the dispatcher database lock.
  346. ;
  347. ifndef NT_UP
  348. cli
  349. cmp dword ptr _KiDispatcherLock, 0
  350. jnz short kdi80
  351. lea ecx, [ebx]+PcPrcbData+PbLockQueue+(8*LockQueueDispatcherLock)
  352. fstCall KeTryToAcquireQueuedSpinLockAtRaisedIrql
  353. jz short kdi80 ; jif not acquired
  354. mov ecx, SYNCH_LEVEL ; raise IRQL to synchronization level
  355. fstCall KfRaiseIrql ;
  356. sti ; enable interrupts
  357. endif
  358. mov eax, [ebx].PcPrcbData.PbNextThread ; get next thread address
  359. ;
  360. ; N.B. The following registers MUST be saved such that ebp is saved last.
  361. ; This is done so the debugger can find the saved ebp for a thread
  362. ; that is not currently in the running state.
  363. ;
  364. .fpo (0, 0, 0, 3, 1, 0)
  365. kdi60: sub esp, 3*4
  366. mov [esp+8], esi ; save registers
  367. mov [esp+4], edi ;
  368. mov [esp+0], ebp ;
  369. mov esi, eax ; set next thread address
  370. mov edi, [ebx].PcPrcbData.PbCurrentThread ; get current thread address
  371. mov dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; clear next thread address
  372. mov [ebx].PcPrcbData.PbCurrentThread, esi ; set current thread address
  373. mov ecx, edi ; set address of current thread
  374. mov byte ptr [edi].ThIdleSwapBlock, 1
  375. fstCall KiReadyThread ; reready thread for execution
  376. CAPSTART <_KiDispatchInterrupt,SwapContext>
  377. mov cl, 1 ; set APC interrupt bypass disable
  378. call SwapContext ; swap context
  379. CAPEND <_KiDispatchInterrupt>
  380. mov ebp, [esp+0] ; restore registers
  381. mov edi, [esp+4] ;
  382. mov esi, [esp+8] ;
  383. add esp, 3*4
  384. kdi70: stdRET _KiDispatchInterrupt ; return
  385. ;
  386. ; Enable interrupts and check DPC queue.
  387. ;
  388. ifndef NT_UP
  389. kdi80: sti ; enable interrupts
  390. YIELD ; rest
  391. jmp kdi00 ;
  392. endif
  393. ;
  394. ; Process quantum end event.
  395. ;
  396. ; N.B. If the quantum end code returns a NULL value, then no next thread
  397. ; has been selected for execution. Otherwise, a next thread has been
  398. ; selected and the dispatcher databased is locked.
  399. ;
  400. kdi90: mov dword ptr [ebx].PcPrcbData.PbQuantumEnd, 0 ; clear quantum end indicator
  401. CAPSTART <_KiDispatchInterrupt,_KiQuantumEnd@0>
  402. stdCall _KiQuantumEnd ; process quantum end
  403. CAPEND <_KiDispatchInterrupt>
  404. or eax, eax ; check if new thread selected
  405. jne kdi60 ; if ne, new thread selected
  406. stdRET _KiDispatchInterrupt ; return
  407. stdENDP _KiDispatchInterrupt
  408. page ,132
  409. subttl "Swap Context to Next Thread"
  410. ;++
  411. ;
  412. ; Routine Description:
  413. ;
  414. ; This routine is called to swap context from one thread to the next.
  415. ; It swaps context, flushes the data, instruction, and translation
  416. ; buffer caches, restores nonvolatile integer registers, and returns
  417. ; to its caller.
  418. ;
  419. ; N.B. It is assumed that the caller (only callers are within this
  420. ; module) saved the nonvolatile registers, ebx, esi, edi, and
  421. ; ebp. This enables the caller to have more registers available.
  422. ;
  423. ; Arguments:
  424. ;
  425. ; cl - APC interrupt bypass disable (zero enable, nonzero disable).
  426. ; edi - Address of previous thread.
  427. ; esi - Address of next thread.
  428. ; ebx - Address of PCR.
  429. ;
  430. ; Return value:
  431. ;
  432. ; al - Kernel APC pending.
  433. ; ebx - Address of PCR.
  434. ; esi - Address of current thread object.
  435. ;
  436. ;--
  437. ;
  438. ; NOTE: The ES: override on the move to ThState is part of the
  439. ; lazy-segment load system. It assures that ES has a valid
  440. ; selector in it, thus preventing us from propagating a bad
  441. ; ES accross a context switch.
  442. ;
  443. ; Note that if segments, other than the standard flat segments,
  444. ; with limits above 2 gig exist, neither this nor the rest of
  445. ; lazy segment loads are reliable.
  446. ;
  447. ; Note that ThState must be set before the dispatcher lock is released
  448. ; to prevent KiSetPriorityThread from seeing a stale value.
  449. ;
  450. ifndef NT_UP
  451. public _ScPatchFxb
  452. public _ScPatchFxe
  453. endif
  454. align 16
  455. public SwapContext
  456. SwapContext proc
  457. ;
  458. ; Save the APC disable flag and set new thread state to running.
  459. ;
  460. or cl, cl ; set zf in flags
  461. mov byte ptr es:[esi]+ThState, Running ; set thread state to running
  462. pushfd
  463. cPublicFpo 0, 1
  464. ;
  465. ; Acquire the context swap lock so the address space of the old process
  466. ; cannot be deleted and then release the dispatcher database lock.
  467. ;
  468. ; N.B. This lock is used to protect the address space until the context
  469. ; switch has sufficiently progressed to the point where the address
  470. ; space is no longer needed. This lock is also acquired by the reaper
  471. ; thread before it finishes thread termination.
  472. ;
  473. ifndef NT_UP
  474. lea ecx, [ebx]+PcPrcbData+PbLockQueue+(8*LockQueueContextSwapLock)
  475. fstCall KeAcquireQueuedSpinLockAtDpcLevel ; Acquire ContextSwap lock
  476. lea ecx, [ebx]+PcPrcbData+PbLockQueue+(8*LockQueueDispatcherLock)
  477. fstCall KeReleaseQueuedSpinLockFromDpcLevel ; release Dispatcher Lock
  478. endif
  479. ;
  480. ; Save the APC disable flag and the exception listhead.
  481. ; (also, check for DPC running which is illegal right now).
  482. ;
  483. SwapContextFromIdle:
  484. mov ecx, [ebx]+PcExceptionList ; save exception list
  485. cmp [ebx]+PcPrcbData+PbDpcRoutineActive, 0
  486. push ecx
  487. cPublicFpo 0, 2
  488. jne sc91 ; bugcheck if DPC active.
  489. ;
  490. ; Check for context swap logging
  491. ;
  492. cmp _PPerfGlobalGroupMask, 0 ; Is the global pointer != null?
  493. jne sc92 ; If not, then check if we are enabled
  494. sc03:
  495. ifndef NT_UP
  496. if DBG
  497. mov cl, [esi]+ThNextProcessor ; get current processor number
  498. cmp cl, [ebx]+PcPrcbData+PbNumber ; same as running processor?
  499. jne sc_error2 ; if ne, processor number mismatch
  500. endif
  501. endif
  502. ;
  503. ; Accumulate the total time spent in a thread.
  504. ;
  505. ifdef PERF_DATA
  506. test _KeFeatureBits, KF_RDTSC ; feature supported?
  507. jz short @f ; if z, feature not present
  508. rdtsc ; read cycle counter
  509. sub eax, [ebx].PcPrcbData.PbThreadStartCount.LiLowPart ; sub off thread
  510. sbb edx, [ebx].PcPrcbData.PbThreadStartCount.LiHighPart ; starting time
  511. add [edi].EtPerformanceCountLow, eax ; accumlate thread run time
  512. adc [edi].EtPerformanceCountHigh, edx ;
  513. add [ebx].PcPrcbData.PbThreadStartCount.LiLowPart, eax ; set new thread
  514. adc [ebx].PcPrcbData.PbThreadStartCount.LiHighPart, edx ; starting time
  515. @@: ;
  516. endif
  517. ;
  518. ; On a uniprocessor system the NPX state is swapped in a lazy manner.
  519. ; If a thread whose state is not in the coprocessor attempts to perform
  520. ; a coprocessor operation, the current NPX state is swapped out (if needed),
  521. ; and the new state is swapped in durning the fault. (KiTrap07)
  522. ;
  523. ; On a multiprocessor system we still fault in the NPX state on demand, but
  524. ; we save the state when the thread switches out (assuming the NPX state
  525. ; was loaded). This is because it could be difficult to obtain the thread's
  526. ; NPX in the trap handler if it was loaded into a different processor's
  527. ; coprocessor.
  528. ;
  529. mov ebp, cr0 ; get current CR0
  530. mov edx, ebp
  531. ifndef NT_UP
  532. cmp byte ptr [edi]+ThNpxState, NPX_STATE_LOADED ; check if NPX state
  533. je sc_save_npx_state
  534. endif
  535. sc05: mov cl, [esi]+ThDebugActive ; get debugger active state
  536. mov [ebx]+PcDebugActive, cl ; set new debugger active state
  537. ;
  538. ; Switch stacks:
  539. ;
  540. ; 1. Save old esp in old thread object.
  541. ; 2. Copy stack base and stack limit into TSS AND PCR
  542. ; 3. Load esp from new thread object
  543. ;
  544. ; Keep interrupts off so we don't confuse the trap handler into thinking
  545. ; we've overrun the kernel stack.
  546. ;
  547. cli ; disable interrupts
  548. mov [edi]+ThKernelStack, esp ; save old kernel stack pointer
  549. mov eax, [esi]+ThInitialStack ; get new initial stack pointer
  550. mov ecx, [esi]+ThStackLimit ; get stack limit
  551. sub eax, NPX_FRAME_LENGTH ; space for NPX_FRAME & NPX CR0 flags
  552. mov [ebx]+PcStackLimit, ecx ; set new stack limit
  553. mov [ebx]+PcInitialStack, eax ; set new stack base
  554. .errnz (NPX_STATE_NOT_LOADED - CR0_TS - CR0_MP)
  555. .errnz (NPX_STATE_LOADED - 0)
  556. ; (eax) = Initial Stack
  557. ; (ebx) = PCR
  558. ; (edi) = OldThread
  559. ; (esi) = NewThread
  560. ; (ebp) = Current CR0
  561. ; (edx) = Current CR0
  562. xor ecx, ecx
  563. mov cl, [esi]+ThNpxState ; New NPX state is (or is not) loaded
  564. and edx, NOT (CR0_MP+CR0_EM+CR0_TS) ; clear thread settable NPX bits
  565. or ecx, edx ; or in new thread's cr0
  566. or ecx, [eax]+FpCr0NpxState ; merge new thread settable state
  567. cmp ebp, ecx ; check if old and new CR0 match
  568. jne sc_reload_cr0 ; if ne, no change in CR0
  569. ;
  570. ; N.B. It is important that the following adjustment NOT be applied to
  571. ; the initial stack value in the PCR. If it is, it will cause the
  572. ; location in memory that the processor pushes the V86 mode segment
  573. ; registers and the first 4 ULONGs in the FLOATING_SAVE_AREA to
  574. ; occupy the same memory locations, which could result in either
  575. ; trashed segment registers in V86 mode, or a trashed NPX state.
  576. ;
  577. ; Adjust ESP0 so that V86 mode threads and 32 bit threads can share
  578. ; a trapframe structure, and the NPX save area will be accessible
  579. ; in the same manner on all threads
  580. ;
  581. ; This test will check the user mode flags. On threads with no user
  582. ; mode context, the value of esp0 does not matter (we will never run
  583. ; in user mode without a usermode context, and if we don't run in user
  584. ; mode the processor will never use the esp0 value.
  585. ;
  586. align 4
  587. sc06: test dword ptr [eax] - KTRAP_FRAME_LENGTH + TsEFlags, EFLAGS_V86_MASK
  588. jnz short sc07 ; if nz, V86 frame, no adjustment
  589. sub eax, TsV86Gs - TsHardwareSegSs ; bias for missing fields
  590. sc07: mov ecx, [ebx]+PcTss ;
  591. mov [ecx]+TssEsp0, eax ;
  592. mov esp, [esi]+ThKernelStack ; set new stack pointer
  593. mov eax, [esi]+ThTeb ; get user TEB address
  594. mov [ebx]+PcTeb, eax ; set user TEB address
  595. sti ; enable interrupts
  596. ;
  597. ; If the new process is not the same as the old process, then switch the
  598. ; address space to the new process.
  599. ;
  600. mov eax, [edi].ThApcState.AsProcess ; get old process address
  601. cmp eax, [esi].ThApcState.AsProcess ; check if process match
  602. ;
  603. ; The old thread is no longer on the processor. It is no longer
  604. ; necessary to protect context swap against an idle processor picking
  605. ; up that thread before it has been completely removed from this
  606. ; processor.
  607. ;
  608. mov byte ptr [edi].ThIdleSwapBlock, 0
  609. jz short sc22 ; if z old process same as new
  610. mov edi, [esi].ThApcState.AsProcess ; get new process address
  611. ;
  612. ; NOTE: Keep KiSwapProcess (below) in sync with this code!
  613. ;
  614. ; Update the processor set masks.
  615. ;
  616. ifndef NT_UP
  617. mov ecx, [ebx]+PcSetMember ; get processor set member
  618. xor [eax]+PrActiveProcessors, ecx ; clear bit in old processor set
  619. xor [edi]+PrActiveProcessors, ecx ; set bit in new processor set
  620. if DBG
  621. test [eax]+PrActiveProcessors, ecx ; test if bit clear in old set
  622. jnz sc_error4 ; if nz, bit not clear in old set
  623. test [edi]+PrActiveProcessors, ecx ; test if bit set in new set
  624. jz sc_error5 ; if z, bit not set in new set
  625. endif
  626. endif
  627. ;
  628. ; LDT switch
  629. ;
  630. test word ptr [edi]+PrLdtDescriptor, 0FFFFH
  631. jnz short sc_load_ldt ; if nz, LDT limit
  632. xor eax, eax ; set LDT NULL
  633. sc21: lldt ax
  634. ;
  635. ; All system structures have been updated, release the context swap
  636. ; lock. This thread is still at raised IRQL so it cannot be context
  637. ; switched, remaining setup can be done without the lock held.
  638. ;
  639. ifndef NT_UP
  640. lea ecx, [ebx]+PcPrcbData+PbLockQueue+(8*LockQueueContextSwapLock)
  641. fstCall KeReleaseQueuedSpinLockFromDpcLevel
  642. endif
  643. ;
  644. ; New CR3, flush tb, sync tss, set IOPM
  645. ; CS, SS, DS, ES all have flat (GDT) selectors in them.
  646. ; FS has the pcr selector.
  647. ; Therefore, GS is only selector we need to flush. We null it out,
  648. ; it will be reloaded from a stack frame somewhere above us.
  649. ; Note: this load of GS before CR3 works around P6 step B0 errata 11
  650. ;
  651. xor eax, eax
  652. mov gs, eax ; (16bit gs = 32bit eax, truncates
  653. ; saves 1 byte, is faster).
  654. mov eax, [edi]+PrDirectoryTableBase ; get new directory base
  655. mov ebp, [ebx]+PcTss ; get new TSS
  656. mov ecx, [edi]+PrIopmOffset ; get IOPM offset
  657. mov [ebp]+TssCR3, eax ; make TSS be in sync with hardware
  658. mov cr3, eax ; flush TLB and set new directory base
  659. mov [ebp]+TssIoMapBase, cx ;
  660. jmp short sc23
  661. ;
  662. ; Release the context swap lock.
  663. ;
  664. align 4
  665. sc22: ;
  666. ifndef NT_UP
  667. lea ecx, [ebx]+PcPrcbData+PbLockQueue+(8*LockQueueContextSwapLock)
  668. fstCall KeReleaseQueuedSpinLockFromDpcLevel
  669. endif
  670. ;
  671. ; Edit the TEB descriptor to point to the TEB
  672. ;
  673. sc23:
  674. mov eax, [ebx]+PcTeb
  675. mov ecx, [ebx]+PcGdt ;
  676. mov [ecx]+(KGDT_R3_TEB+KgdtBaseLow), ax ;
  677. shr eax, 16 ;
  678. mov [ecx]+(KGDT_R3_TEB+KgdtBaseMid), al ;
  679. mov [ecx]+(KGDT_R3_TEB+KgdtBaseHi), ah
  680. ;
  681. ; Update context switch counters.
  682. ;
  683. inc dword ptr [esi]+ThContextSwitches ; thread count
  684. inc dword ptr [ebx]+PcPrcbData+PbContextSwitches ; processor count
  685. pop ecx ; restore exception list
  686. mov [ebx].PcExceptionList, ecx ;
  687. ;
  688. ; If the new thread has a kernel mode APC pending, then request an APC
  689. ; interrupt.
  690. ;
  691. cmp byte ptr [esi].ThApcState.AsKernelApcPending, 0 ; APC pending?
  692. jne short sc80 ; if ne, kernel APC pending
  693. popfd ; restore flags
  694. xor eax, eax ; clear kernel APC pending
  695. ret ; return
  696. ;
  697. ; The new thread has an APC interrupt pending. If APC interrupt bypass is
  698. ; enable, then return kernel APC pending. Otherwise, request a software
  699. ; interrupt at APC_LEVEL and return no kernel APC pending.
  700. ;
  701. sc80: popfd ; restore flags
  702. jnz short sc90 ; if nz, APC interupt bypass disabled
  703. mov al, 1 ; set kernel APC pending
  704. ret ;
  705. sc90: mov cl, APC_LEVEL ; request software interrupt level
  706. fstCall HalRequestSoftwareInterrupt ;
  707. xor eax, eax ; clear kernel APC pending
  708. ret ;
  709. ;
  710. ; Set for new LDT value
  711. ;
  712. sc_load_ldt:
  713. mov ebp, [ebx]+PcGdt ;
  714. mov eax, [edi+PrLdtDescriptor] ;
  715. mov [ebp+KGDT_LDT], eax ;
  716. mov eax, [edi+PrLdtDescriptor+4] ;
  717. mov [ebp+KGDT_LDT+4], eax ;
  718. mov eax, KGDT_LDT ;
  719. ;
  720. ; Set up int 21 descriptor of IDT. If the process does not have an Ldt, it
  721. ; should never make any int 21 calls. If it does, an exception is generated. If
  722. ; the process has an Ldt, we need to update int21 entry of LDT for the process.
  723. ; Note the Int21Descriptor of the process may simply indicate an invalid
  724. ; entry. In which case, the int 21 will be trapped to the kernel.
  725. ;
  726. mov ebp, [ebx]+PcIdt ;
  727. mov ecx, [edi+PrInt21Descriptor] ;
  728. mov [ebp+21h*8], ecx ;
  729. mov ecx, [edi+PrInt21Descriptor+4] ;
  730. mov [ebp+21h*8+4], ecx ;
  731. jmp sc21
  732. ;
  733. ; Cr0 has changed (ie, floating point processor present), load the new value.
  734. ;
  735. sc_reload_cr0:
  736. if DBG
  737. test byte ptr [esi]+ThNpxState, NOT (CR0_TS+CR0_MP)
  738. jnz sc_error ;
  739. test dword ptr [eax]+FpCr0NpxState, NOT (CR0_PE+CR0_MP+CR0_EM+CR0_TS)
  740. jnz sc_error3 ;
  741. endif
  742. mov cr0,ecx ; set new CR0 NPX state
  743. jmp sc06
  744. ifndef NT_UP
  745. ; Save coprocessor's current context. FpCr0NpxState is the current thread's
  746. ; CR0 state. The following bits are valid: CR0_MP, CR0_EM, CR0_TS. MVDMs
  747. ; may set and clear MP & EM as they please and the settings will be reloaded
  748. ; on a context switch (but they will not be saved from CR0 to Cr0NpxState).
  749. ; The kernel sets and clears TS as required.
  750. ;
  751. ; (ebp) = Current CR0
  752. ; (edx) = Current CR0
  753. sc_save_npx_state:
  754. and edx, NOT (CR0_MP+CR0_EM+CR0_TS) ; we need access to the NPX state
  755. mov ecx,[ebx]+PcInitialStack ; get NPX save save area address
  756. cmp ebp, edx ; Does CR0 need reloading?
  757. je short sc_npx10
  758. mov cr0, edx ; set new cr0
  759. mov ebp, edx ; (ebp) = (edx) = current cr0 state
  760. sc_npx10:
  761. ;
  762. ; The fwait following the fnsave is to make sure that the fnsave has stored the
  763. ; data into the save area before this coprocessor state could possibly be
  764. ; context switched in and used on a different (co)processor. I've added the
  765. ; clocks from when the dispatcher lock is released and don't believe it's a
  766. ; possibility. I've also timed the impact this fwait seems to have on a 486
  767. ; when performing lots of numeric calculations. It appears as if there is
  768. ; nothing to wait for after the fnsave (although the 486 manual says there is)
  769. ; and therefore the calculation time far outweighed the 3clk fwait and it
  770. ; didn't make a noticable difference.
  771. ;
  772. ;
  773. ; If FXSR feature is NOT present on the processor, the fxsave instruction is
  774. ; patched at boot time to start using fnsave instead
  775. ;
  776. _ScPatchFxb:
  777. ; fxsave [ecx] ; save NPX state
  778. db 0FH, 0AEH, 01
  779. _ScPatchFxe:
  780. mov byte ptr [edi]+ThNpxState, NPX_STATE_NOT_LOADED ; set no NPX state
  781. mov dword ptr [ebx].PcPrcbData+PbNpxThread, 0 ; clear npx owner
  782. jmp sc05
  783. endif
  784. ;
  785. ; This code is out of line to optimize the normal case
  786. ; (which is expected to be the case where tracing is off)
  787. ; First we grab the pointer to our flags struct and place it in eax.
  788. ; To take advantage of spare cycles while the load is occuring, we
  789. ; prepare for our upcoming funciton call by copying parameters between regs.
  790. ; Next we dereference that pointer plus the offset of the flag we need
  791. ; to check and bitwise AND that value with our flag. If the result is
  792. ; nonzero, then we make the function call to trace this context swap.
  793. ;
  794. ; NOTE: The flags struct is a static global.
  795. ;
  796. sc92:
  797. mov eax, _PPerfGlobalGroupMask ; Load the ptr into eax
  798. cmp eax, 0 ; catch race here
  799. jz sc03
  800. mov edx, esi ; pass the new ETHREAD object
  801. mov ecx, edi ; pass the old ETHREAD object
  802. test dword ptr [eax+PERF_CONTEXTSWAP_OFFSET], PERF_CONTEXTSWAP_FLAG
  803. jz sc03 ; return if our flag is not set
  804. fstCall WmiTraceContextSwap ; call the Wmi context swap trace
  805. jmp sc03
  806. .fpo (2, 0, 0, 0, 0, 0)
  807. sc91: stdCall _KeBugCheck <ATTEMPTED_SWITCH_FROM_DPC>
  808. ret ; return
  809. if DBG
  810. sc_error5: int 3
  811. sc_error4: int 3
  812. sc_error3: int 3
  813. sc_error2: int 3
  814. sc_error: int 3
  815. endif
  816. SwapContext endp
  817. page , 132
  818. subttl "Interlocked Swap PTE"
  819. ;++
  820. ;
  821. ; HARDWARE_PTE
  822. ; KeInterlockedSwapPte (
  823. ; IN PKI_INTERNAL_PTE PtePointer,
  824. ; IN PKI_INTERNAL_PTE NewPteContents
  825. ; )
  826. ;
  827. ; Routine Description:
  828. ;
  829. ; This function performs an interlocked swap of a PTE. This is only needed
  830. ; for the PAE architecture where the PTE width is larger than the register
  831. ; width.
  832. ;
  833. ; Both PTEs must be valid or a careful write would have been done instead.
  834. ;
  835. ; Arguments:
  836. ;
  837. ; PtePointer - Address of Pte to update with new value.
  838. ;
  839. ; NewPteContents - Pointer to the new value to put in the Pte. Will simply
  840. ; be assigned to *PtePointer, in a fashion correct for the hardware.
  841. ;
  842. ; Return Value:
  843. ;
  844. ; Returns the contents of the PtePointer before the new value
  845. ; is stored.
  846. ;
  847. ;--
  848. cPublicProc _KeInterlockedSwapPte ,2
  849. push ebx
  850. push esi
  851. mov ebx, [esp] + 16 ; ebx = NewPteContents
  852. mov esi, [esp] + 12 ; esi = PtePointer
  853. mov ecx, [ebx] + 4
  854. mov ebx, [ebx] ; ecx:ebx = source pte contents
  855. mov edx, [esi] + 4
  856. mov eax, [esi] ; edx:eax = target pte contents
  857. swapagain:
  858. ;
  859. ; cmpxchg loads edx:eax with the new contents of the target quadword
  860. ; in the event of failure
  861. ;
  862. ifndef NT_UP
  863. lock cmpxchg8b qword ptr [esi] ; compare and exchange
  864. else
  865. cmpxchg8b qword ptr [esi] ; compare and exchange
  866. endif
  867. jnz short swapagain ; if z clear, exchange failed
  868. pop esi
  869. pop ebx
  870. stdRET _KeInterlockedSwapPte
  871. stdENDP _KeInterlockedSwapPte
  872. page , 132
  873. subttl "Flush EntireTranslation Buffer"
  874. ;++
  875. ;
  876. ; VOID
  877. ; KeFlushCurrentTb (
  878. ; )
  879. ;
  880. ; Routine Description:
  881. ;
  882. ; This function flushes the entire translation buffer (TB) on the current
  883. ; processor and also flushes the data cache if an entry in the translation
  884. ; buffer has become invalid.
  885. ;
  886. ; Arguments:
  887. ;
  888. ; Return Value:
  889. ;
  890. ; None.
  891. ;
  892. ;--
  893. cPublicProc _KeFlushCurrentTb ,0
  894. ktb00: mov eax, cr3 ; (eax) = directory table base
  895. mov cr3, eax ; flush TLB
  896. stdRET _KeFlushCurrentTb
  897. ktb_gb: mov eax, cr4 ; *** see Ki386EnableGlobalPage ***
  898. and eax, not CR4_PGE ; This FlushCurrentTb version gets copied into
  899. mov cr4, eax ; ktb00 at initialization time if needed.
  900. or eax, CR4_PGE
  901. mov cr4, eax
  902. ktb_eb: stdRET _KeFlushCurrentTb
  903. stdENDP _KeFlushCurrentTb
  904. ;;
  905. ;; moved KiFlushDcache below KeFlushCurrentTb for BBT purposes. BBT
  906. ;; needs an end label to treat KeFlushCurrentTb as data and to keep together.
  907. ;;
  908. page , 132
  909. subttl "Flush Data Cache"
  910. ;++
  911. ;
  912. ; VOID
  913. ; KiFlushDcache (
  914. ; )
  915. ;
  916. ; VOID
  917. ; KiFlushIcache (
  918. ; )
  919. ;
  920. ; Routine Description:
  921. ;
  922. ; This routine does nothing on i386 and i486 systems. Why? Because
  923. ; (a) their caches are completely transparent, (b) they don't have
  924. ; instructions to flush their caches.
  925. ;
  926. ; Arguments:
  927. ;
  928. ; None.
  929. ;
  930. ; Return Value:
  931. ;
  932. ; None.
  933. ;
  934. ;--
  935. cPublicProc _KiFlushDcache ,0
  936. cPublicProc _KiFlushIcache ,0
  937. stdRET _KiFlushIcache
  938. stdENDP _KiFlushIcache
  939. stdENDP _KiFlushDcache
  940. _TEXT$00 ends
  941. INIT SEGMENT DWORD PUBLIC 'CODE'
  942. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  943. ;++
  944. ;
  945. ; VOID
  946. ; Ki386EnableGlobalPage (
  947. ; IN volatile PLONG Number
  948. ; )
  949. ;
  950. ; /*++
  951. ;
  952. ; Routine Description:
  953. ;
  954. ; This routine enables the global page PDE/PTE support in the system,
  955. ; and stalls until complete and them sets the current processor's cr4
  956. ; register to enable global page support.
  957. ;
  958. ; Arguments:
  959. ;
  960. ; Number - Supplies a pointer to the count of the number of processors in
  961. ; the configuration.
  962. ;
  963. ; Return Value:
  964. ;
  965. ; None.
  966. ;--
  967. cPublicProc _Ki386EnableGlobalPage,1
  968. push esi
  969. push edi
  970. push ebx
  971. mov edx, [esp+16] ; pointer to Number
  972. pushfd
  973. cli
  974. ;
  975. ; Wait for all processors
  976. ;
  977. lock dec dword ptr [edx] ; count down
  978. egp10: YIELD
  979. cmp dword ptr [edx], 0 ; wait for all processors to signal
  980. jnz short egp10
  981. cmp byte ptr PCR[PcNumber], 0 ; processor 0?
  982. jne short egp20
  983. ;
  984. ; Install proper KeFlushCurrentTb function.
  985. ;
  986. mov edi, ktb00
  987. mov esi, ktb_gb
  988. mov ecx, ktb_eb - ktb_gb + 1
  989. rep movsb
  990. mov byte ptr [ktb_eb], 0
  991. ;
  992. ; Wait for P0 to signal that proper flush TB handlers have been installed
  993. ;
  994. egp20: cmp byte ptr [ktb_eb], 0
  995. jnz short egp20
  996. ;
  997. ; Flush TB, and enable global page support
  998. ; (note load of CR4 is explicitly done before the load of CR3
  999. ; to work around P6 step B0 errata 11)
  1000. ;
  1001. mov eax, cr4
  1002. and eax, not CR4_PGE ; should not be set, but let's be safe
  1003. mov ecx, cr3
  1004. mov cr4, eax
  1005. mov cr3, ecx ; Flush TB
  1006. or eax, CR4_PGE ; enable global TBs
  1007. mov cr4, eax
  1008. popfd
  1009. pop ebx
  1010. pop edi
  1011. pop esi
  1012. stdRET _Ki386EnableGlobalPage
  1013. stdENDP _Ki386EnableGlobalPage
  1014. ;++
  1015. ;
  1016. ; VOID
  1017. ; Ki386EnableDE (
  1018. ; IN volatile PLONG Number
  1019. ; )
  1020. ;
  1021. ; /*++
  1022. ;
  1023. ; Routine Description:
  1024. ;
  1025. ; This routine sets DE bit in CR4 to enable IO breakpoints
  1026. ;
  1027. ; Arguments:
  1028. ;
  1029. ; Number - Supplies a pointer to the count of the number of processors in
  1030. ; the configuration.
  1031. ;
  1032. ; Return Value:
  1033. ;
  1034. ; None.
  1035. ;--
  1036. cPublicProc _Ki386EnableDE,1
  1037. mov eax, cr4
  1038. or eax, CR4_DE
  1039. mov cr4, eax
  1040. stdRET _Ki386EnableDE
  1041. stdENDP _Ki386EnableDE
  1042. ;++
  1043. ;
  1044. ; VOID
  1045. ; Ki386EnableFxsr (
  1046. ; IN volatile PLONG Number
  1047. ; )
  1048. ;
  1049. ; /*++
  1050. ;
  1051. ; Routine Description:
  1052. ;
  1053. ; This routine sets OSFXSR bit in CR4 to indicate that OS supports
  1054. ; FXSAVE/FXRSTOR for use during context switches
  1055. ;
  1056. ; Arguments:
  1057. ;
  1058. ; Number - Supplies a pointer to the count of the number of processors in
  1059. ; the configuration.
  1060. ;
  1061. ; Return Value:
  1062. ;
  1063. ; None.
  1064. ;--
  1065. cPublicProc _Ki386EnableFxsr,1
  1066. mov eax, cr4
  1067. or eax, CR4_FXSR
  1068. mov cr4, eax
  1069. stdRET _Ki386EnableFxsr
  1070. stdENDP _Ki386EnableFxsr
  1071. ;++
  1072. ;
  1073. ; VOID
  1074. ; Ki386EnableXMMIExceptions (
  1075. ; IN volatile PLONG Number
  1076. ; )
  1077. ;
  1078. ; /*++
  1079. ;
  1080. ; Routine Description:
  1081. ;
  1082. ; This routine installs int 19 XMMI unmasked Numeric Exception handler
  1083. ; and sets OSXMMEXCPT bit in CR4 to indicate that OS supports
  1084. ; unmasked Katmai New Instruction technology exceptions.
  1085. ;
  1086. ; Arguments:
  1087. ;
  1088. ; Number - Supplies a pointer to count of the number of processors in
  1089. ; the configuration.
  1090. ;
  1091. ; Return Value:
  1092. ;
  1093. ; None.
  1094. ;--
  1095. cPublicProc _Ki386EnableXMMIExceptions,1
  1096. ;Set up IDT for INT19
  1097. mov ecx,PCR[PcIdt] ;Get IDT address
  1098. lea eax, [ecx] + 098h ;XMMI exception is int 19
  1099. mov byte ptr [eax + 5], 08eh ;P=1,DPL=0,Type=e
  1100. mov word ptr [eax + 2], KGDT_R0_CODE ;Kernel code selector
  1101. mov edx, offset FLAT:_KiTrap13 ;Address of int 19 handler
  1102. mov ecx,edx
  1103. mov word ptr [eax],cx ;addr moves into low byte
  1104. shr ecx,16
  1105. mov word ptr [eax + 6],cx ;addr moves into high byte
  1106. ;Enable XMMI exception handling
  1107. mov eax, cr4
  1108. or eax, CR4_XMMEXCPT
  1109. mov cr4, eax
  1110. stdRET _Ki386EnableXMMIExceptions
  1111. stdENDP _Ki386EnableXMMIExceptions
  1112. ;++
  1113. ;
  1114. ; VOID
  1115. ; Ki386EnableCurrentLargePage (
  1116. ; IN ULONG IdentityAddr,
  1117. ; IN ULONG IdentityCr3
  1118. ; )
  1119. ;
  1120. ; /*++
  1121. ;
  1122. ; Routine Description:
  1123. ;
  1124. ; This routine enables the large page PDE support in the processor.
  1125. ;
  1126. ; Arguments:
  1127. ;
  1128. ; IdentityAddr - Supplies the linear address of the beginning of this
  1129. ; function where (linear == physical).
  1130. ;
  1131. ; IdentityCr3 - Supplies a pointer to the temporary page directory and
  1132. ; page tables that provide both the kernel (virtual ->physical) and
  1133. ; identity (linear->physical) mappings needed for this function.
  1134. ;
  1135. ; Return Value:
  1136. ;
  1137. ; None.
  1138. ;--
  1139. public _Ki386EnableCurrentLargePageEnd
  1140. cPublicProc _Ki386EnableCurrentLargePage,2
  1141. mov ecx,[esp]+4 ; (ecx)-> IdentityAddr
  1142. mov edx,[esp]+8 ; (edx)-> IdentityCr3
  1143. pushfd ; save current IF state
  1144. cli ; disable interrupts
  1145. mov eax, cr3 ; (eax)-> original Cr3
  1146. mov cr3, edx ; load Cr3 with Identity mapping
  1147. sub ecx, offset _Ki386EnableCurrentLargePage
  1148. add ecx, offset _Ki386LargePageIdentityLabel
  1149. jmp ecx ; jump to (linear == physical)
  1150. _Ki386LargePageIdentityLabel:
  1151. mov ecx, cr0
  1152. and ecx, NOT CR0_PG ; clear PG bit to disable paging
  1153. mov cr0, ecx ; disable paging
  1154. jmp $+2
  1155. mov edx, cr4
  1156. or edx, CR4_PSE ; enable Page Size Extensions
  1157. mov cr4, edx
  1158. mov edx, offset OriginalMapping
  1159. or ecx, CR0_PG ; set PG bit to enable paging
  1160. mov cr0, ecx ; enable paging
  1161. jmp edx ; Return to original mapping.
  1162. OriginalMapping:
  1163. mov cr3, eax ; restore original Cr3
  1164. popfd ; restore interrupts to previous
  1165. stdRET _Ki386EnableCurrentLargePage
  1166. _Ki386EnableCurrentLargePageEnd:
  1167. stdENDP _Ki386EnableCurrentLargePage
  1168. INIT ends
  1169. _TEXT$00 SEGMENT PARA PUBLIC 'CODE'
  1170. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  1171. page , 132
  1172. subttl "Flush Single Translation Buffer"
  1173. ;++
  1174. ;
  1175. ; VOID
  1176. ; FASTCALL
  1177. ; KiFlushSingleTb (
  1178. ; IN BOOLEAN Invalid,
  1179. ; IN PVOID Virtual
  1180. ; )
  1181. ;
  1182. ; Routine Description:
  1183. ;
  1184. ; This function flushes a single TB entry.
  1185. ;
  1186. ; It only works on a 486 or greater.
  1187. ;
  1188. ; Arguments:
  1189. ;
  1190. ; Invalid - Supplies a boolean value that specifies the reason for
  1191. ; flushing the translation buffer.
  1192. ;
  1193. ; Virtual - Supplies the virtual address of the single entry that is
  1194. ; to be flushed from the translation buffer.
  1195. ;
  1196. ; Return Value:
  1197. ;
  1198. ; None.
  1199. ;
  1200. ;--
  1201. cPublicFastCall KiFlushSingleTb ,2
  1202. ;
  1203. ; 486 or above code
  1204. ;
  1205. invlpg [edx]
  1206. fstRET KiFlushSingleTb
  1207. fstENDP KiFlushSingleTb
  1208. page , 132
  1209. subttl "Swap Process"
  1210. ;++
  1211. ;
  1212. ; VOID
  1213. ; KiSwapProcess (
  1214. ; IN PKPROCESS NewProcess,
  1215. ; IN PKPROCESS OldProcess
  1216. ; )
  1217. ;
  1218. ; Routine Description:
  1219. ;
  1220. ; This function swaps the address space to another process by flushing
  1221. ; the data cache, the instruction cache, the translation buffer, and
  1222. ; establishes a new directory table base.
  1223. ;
  1224. ; It also swaps in the LDT and IOPM of the new process. This is necessary
  1225. ; to avoid bogus mismatches in SwapContext.
  1226. ;
  1227. ; NOTE: keep in sync with process switch part of SwapContext
  1228. ;
  1229. ; Arguments:
  1230. ;
  1231. ; Process - Supplies a pointer to a control object of type process.
  1232. ;
  1233. ; Return Value:
  1234. ;
  1235. ; None.
  1236. ;
  1237. ;--
  1238. cPublicProc _KiSwapProcess ,2
  1239. cPublicFpo 2, 0
  1240. ifndef NT_UP
  1241. ;
  1242. ; Acquire the context swap lock.
  1243. ;
  1244. mov ecx, PCR[PcPrcb]
  1245. lea ecx, [ecx]+PbLockQueue+(8*LockQueueContextSwapLock)
  1246. fstCall KeAcquireQueuedSpinLockAtDpcLevel
  1247. mov edx,[esp]+4 ; (edx)-> New process
  1248. mov eax,[esp]+8 ; (eax)-> Old Process
  1249. ;
  1250. ; Clear the processor set member in the old process, set the processor
  1251. ; member in the new process, and release the context swap lock.
  1252. ;
  1253. mov ecx, PCR[PcSetMember]
  1254. xor [eax]+PrActiveProcessors,ecx ; clear bit in old processor set
  1255. xor [edx]+PrActiveProcessors,ecx ; set bit in new processor set
  1256. if DBG
  1257. test [eax]+PrActiveProcessors,ecx ; test if bit clear in old set
  1258. jnz kisp_error ; if nz, bit not clear in old set
  1259. test [edx]+PrActiveProcessors,ecx ; test if bit set in new set
  1260. jz kisp_error1 ; if z, bit not set in new set
  1261. endif
  1262. mov ecx, PCR[PcPrcb]
  1263. lea ecx, [ecx]+PbLockQueue+(8*LockQueueContextSwapLock)
  1264. fstCall KeReleaseQueuedSpinLockFromDpcLevel
  1265. endif
  1266. mov ecx,PCR[PcTss] ; (ecx)-> TSS
  1267. mov edx,[esp]+4 ; (edx)-> New process
  1268. ;
  1269. ; Change address space
  1270. ;
  1271. xor eax,eax ; assume ldtr is to be NULL
  1272. mov gs,ax ; Clear gs. (also workarounds
  1273. ; P6 step B0 errata 11)
  1274. mov eax,[edx]+PrDirectoryTableBase
  1275. mov [ecx]+TssCR3,eax ; be sure TSS in sync with processor
  1276. mov cr3,eax
  1277. ;
  1278. ; Change IOPM
  1279. ;
  1280. mov ax,[edx]+PrIopmOffset
  1281. mov [ecx]+TssIoMapBase,ax
  1282. ;
  1283. ; Change LDT
  1284. ;
  1285. xor eax, eax
  1286. cmp word ptr [edx]+PrLdtDescriptor,ax ; limit 0?
  1287. jz short kisp10 ; null LDT, go load NULL ldtr
  1288. ;
  1289. ; Edit LDT descriptor
  1290. ;
  1291. mov ecx,PCR[PcGdt]
  1292. mov eax,[edx+PrLdtDescriptor]
  1293. mov [ecx+KGDT_LDT],eax
  1294. mov eax,[edx+PrLdtDescriptor+4]
  1295. mov [ecx+KGDT_LDT+4],eax
  1296. ;
  1297. ; Set up int 21 descriptor of IDT. If the process does not have Ldt, it
  1298. ; should never make any int 21 call. If it does, an exception is generated.
  1299. ; If the process has Ldt, we need to update int21 entry of LDT for the process.
  1300. ; Note the Int21Descriptor of the process may simply indicate an invalid
  1301. ; entry. In which case, the int 21 will be trapped to the kernel.
  1302. ;
  1303. mov ecx, PCR[PcIdt]
  1304. mov eax, [edx+PrInt21Descriptor]
  1305. mov [ecx+21h*8], eax
  1306. mov eax, [edx+PrInt21Descriptor+4]
  1307. mov [ecx+21h*8+4], eax
  1308. mov eax,KGDT_LDT ;@@32-bit op to avoid prefix
  1309. ;
  1310. ; Load LDTR
  1311. ;
  1312. kisp10: lldt ax
  1313. stdRET _KiSwapProcess
  1314. if DBG
  1315. kisp_error1: int 3
  1316. kisp_error: int 3
  1317. endif
  1318. stdENDP _KiSwapProcess
  1319. page ,132
  1320. subttl "Idle Loop"
  1321. ;++
  1322. ;
  1323. ; VOID
  1324. ; KiIdleLoop(
  1325. ; VOID
  1326. ; )
  1327. ;
  1328. ; Routine Description:
  1329. ;
  1330. ; This routine continuously executes the idle loop and never returns.
  1331. ;
  1332. ; Arguments:
  1333. ;
  1334. ; ebx - Address of the current processor's PCR.
  1335. ;
  1336. ; Return value:
  1337. ;
  1338. ; None - routine never returns.
  1339. ;
  1340. ;--
  1341. cPublicFastCall KiIdleLoop ,0
  1342. cPublicFpo 0, 0
  1343. lea ebp, [ebx].PcPrcbData.PbDpcListHead ; set DPC listhead address
  1344. if DBG
  1345. xor edi, edi ; reset poll breakin counter
  1346. endif
  1347. jmp short kid20 ; Skip HalIdleProcessor on first iteration
  1348. ;
  1349. ; There are no entries in the DPC list and a thread has not been selected
  1350. ; for execution on this processor. Call the HAL so power managment can be
  1351. ; performed.
  1352. ;
  1353. ; N.B. The HAL is called with interrupts disabled. The HAL will return
  1354. ; with interrupts enabled.
  1355. ;
  1356. ; N.B. Use a call instruction instead of a push-jmp, as the call instruction
  1357. ; executes faster and won't invalidate the processor's call-return stack
  1358. ; cache.
  1359. ;
  1360. kid10: lea ecx, [ebx].PcPrcbData.PbPowerState
  1361. call dword ptr [ecx].PpIdleFunction ; (ecx) = Arg0
  1362. ;
  1363. ; Give the debugger an opportunity to gain control on debug systems.
  1364. ;
  1365. ; N.B. On an MP system the lowest numbered idle processor is the only
  1366. ; processor that polls for a breakin request.
  1367. ;
  1368. kid20:
  1369. if DBG
  1370. ifndef NT_UP
  1371. mov eax, _KiIdleSummary ; get idle summary
  1372. mov ecx, [ebx].PcSetMember ; get set member
  1373. dec ecx ; compute right bit mask
  1374. and eax, ecx ; check if any lower bits set
  1375. jnz short CheckDpcList ; if nz, not lowest numbered
  1376. endif
  1377. dec edi ; decrement poll counter
  1378. jg short CheckDpcList ; if g, not time to poll
  1379. POLL_DEBUGGER ; check if break in requested
  1380. endif
  1381. kid30:
  1382. if DBG
  1383. ifndef NT_UP
  1384. mov edi, 20 * 1000 ; set breakin poll interval
  1385. else
  1386. mov edi, 100 ; UP idle loop has a HLT in it
  1387. endif
  1388. endif
  1389. CheckDpcList0:
  1390. YIELD
  1391. ;
  1392. ; Disable interrupts and check if there is any work in the DPC list
  1393. ; of the current processor or a target processor.
  1394. ;
  1395. CheckDpcList:
  1396. ;
  1397. ; N.B. The following code enables interrupts for a few cycles, then
  1398. ; disables them again for the subsequent DPC and next thread
  1399. ; checks.
  1400. ;
  1401. sti ; enable interrupts
  1402. nop ;
  1403. nop ;
  1404. cli ; disable interrupts
  1405. ;
  1406. ; Process the deferred procedure call list for the current processor.
  1407. ;
  1408. cmp ebp, [ebp].LsFlink ; check if DPC list is empty
  1409. je short CheckNextThread ; if eq, DPC list is empty
  1410. mov cl, DISPATCH_LEVEL ; set interrupt level
  1411. fstCall HalClearSoftwareInterrupt ; clear software interrupt
  1412. CAPSTART <@KiIdleLoop@0,KiRetireDpcList>
  1413. call KiRetireDpcList ; process the current DPC list
  1414. CAPEND <@KiIdleLoop@0>
  1415. if DBG
  1416. xor edi, edi ; clear breakin poll interval
  1417. endif
  1418. ;
  1419. ; Check if a thread has been selected to run on the current processor.
  1420. ;
  1421. CheckNextThread: ;
  1422. cmp dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; thread selected?
  1423. je short kid10 ; if eq, no thread selected
  1424. ifndef NT_UP
  1425. ;
  1426. ; A thread has been selected for execution on this processor. Acquire
  1427. ; the dispatcher database lock, get the thread address again (it may have
  1428. ; changed), clear the address of the next thread in the processor block,
  1429. ; and call swap context to start execution of the selected thread.
  1430. ;
  1431. ; N.B. If the dispatcher database lock cannot be obtained immediately,
  1432. ; then attempt to process another DPC rather than spinning on the
  1433. ; dispatcher database lock.
  1434. ; N.B. On MP systems, the dispatcher database is always locked at
  1435. ; SYNCH level to ensure the lock is held for as short a period as
  1436. ; possible (reduce contention). On UP systems there really is no
  1437. ; lock, it is sufficient to be at DISPATCH level (which is the
  1438. ; current level at this point in the code).
  1439. ;
  1440. ; Raise IRQL to synchronization level and enable interrupts.
  1441. ;
  1442. mov ecx, SYNCH_LEVEL ; raise IRQL to synchronization level
  1443. fstCall KfRaiseIrql ;
  1444. endif
  1445. sti ; enable interrupts
  1446. ifndef NT_UP
  1447. ;
  1448. ; Acquire the context swap lock, this must be done with interrupts
  1449. ; enabled to avoid deadlocks with processors that receive IPIs while
  1450. ; holding the dispatcher lock.
  1451. ;
  1452. ; N.B. KeAcquireQueuedSpinLockAtDpcLevel doesn't touch IRQL, it
  1453. ; is OK that we are at SYNCH level at this time.
  1454. lea ecx, [ebx]+PcPrcbData+PbLockQueue+(8*LockQueueContextSwapLock)
  1455. fstCall KeAcquireQueuedSpinLockAtDpcLevel
  1456. endif
  1457. kidsw: mov esi, [ebx].PcPrcbData.PbNextThread ; get next thread address
  1458. mov edi, [ebx].PcPrcbData.PbCurrentThread ; get current thread address
  1459. ifndef NT_UP
  1460. cmp byte ptr [esi].ThIdleSwapBlock, 0
  1461. jne short kidndl
  1462. ;
  1463. ; If a thread had been scheduled for this processor but was removed from
  1464. ; from eligibility (eg AffinitySet to not include this processor), then
  1465. ; the NextThread could be the idle thread and this processor is marked
  1466. ; as idle (again). In this case, the scheduler may assign another thread
  1467. ; to this processor in the window between reading the NextThread field
  1468. ; above, and zeroing it below.
  1469. ;
  1470. ; Detection of this condition is done here because this processor is not
  1471. ; otherwise busy.
  1472. ;
  1473. cmp esi, edi
  1474. je short kisame
  1475. endif
  1476. or ecx, 1 ; set APC disable
  1477. mov [ebx].PcPrcbData.PbCurrentThread, esi
  1478. ;
  1479. ; Other processors might be examining the Prcb->CurrentThread entry
  1480. ; for this processor while holding the dispatcher database lock
  1481. ; which is not held here. However, they always check the NextThread
  1482. ; field first and if non NULL will acquire the context swap lock.
  1483. ; Setting the CurrentThread field before clearing the NextThread
  1484. ; field assures correct locking semantics.
  1485. ;
  1486. mov byte ptr es:[esi]+ThState, Running ; set thread state running
  1487. mov dword ptr [ebx].PcPrcbData.PbNextThread, 0
  1488. CAPSTART <@KiIdleLoop@0,SwapContext>
  1489. ;
  1490. ; Set the stack as though code from SwapContext thru SwapContextFromIdle
  1491. ; had been executed.
  1492. ;
  1493. push FLAT:@f ; set return address
  1494. pushfd ; set saved flags
  1495. jmp SwapContextFromIdle
  1496. @@:
  1497. CAPEND <@KiIdleLoop@0>
  1498. ifndef NT_UP
  1499. mov ecx, DISPATCH_LEVEL ; lower IRQL to dispatch level
  1500. fstCall KfLowerIrql ;
  1501. endif
  1502. lea ebp, [ebx].PcPrcbData.PbDpcListHead ; set DPC listhead address
  1503. jmp kid30 ;
  1504. ifndef NT_UP
  1505. ;
  1506. ; The new thread is still on another processor and cannot be switched to
  1507. ; yet. Drop the context swap lock and take another pass around the idle
  1508. ; loop.
  1509. ;
  1510. kidndl: lea ecx, [ebx]+PcPrcbData+PbLockQueue+(8*LockQueueContextSwapLock)
  1511. @@: fstCall KeReleaseQueuedSpinLockFromDpcLevel
  1512. mov ecx, DISPATCH_LEVEL ; lower IRQL to dispatch level
  1513. fstCall KfLowerIrql ;
  1514. lea ebp, [ebx].PcPrcbData.PbDpcListHead ; set DPC listhead address
  1515. jmp kid30 ;
  1516. ;
  1517. ; The new thread is the Idle thread (same as old thread). This can happen
  1518. ; rarely when a thread scheduled for this processor is made unable to run
  1519. ; on this processor. As this processor has again been marked idle, other
  1520. ; processors may unconditionally assign new threads to this processor.
  1521. ;
  1522. ; Acquire the dispatcher database lock to protect against this condition.
  1523. ;
  1524. kisame: lea ecx, [ebx]+PcPrcbData+PbLockQueue+(8*LockQueueContextSwapLock)
  1525. fstCall KeReleaseQueuedSpinLockFromDpcLevel
  1526. lea ecx, [ebx]+PcPrcbData+PbLockQueue+(8*LockQueueDispatcherLock)
  1527. fstCall KeAcquireQueuedSpinLockAtDpcLevel
  1528. ;
  1529. ; At this time, the NextThread field may have changed, if not, it is safe
  1530. ; to clear it under the protection of the dispatcher lock. If it has
  1531. ; changed, don't clear it.
  1532. ;
  1533. cmp esi, [ebx].PcPrcbData.PbNextThread
  1534. jne short @b
  1535. mov dword ptr [ebx].PcPrcbData.PbNextThread, 0
  1536. ;
  1537. ; Release the dispatcher database lock and continue executing the idle
  1538. ; loop. N.B. ecx still contains the address of the dispatcher database
  1539. ; lock.
  1540. ;
  1541. jmp short @b
  1542. endif
  1543. fstENDP KiIdleLoop
  1544. page ,132
  1545. subttl "Retire Deferred Procedure Call List"
  1546. ;++
  1547. ;
  1548. ; Routine Description:
  1549. ;
  1550. ; This routine is called to retire the specified deferred procedure
  1551. ; call list. DPC routines are called using the idle thread (current)
  1552. ; stack.
  1553. ;
  1554. ; N.B. Interrupts must be disabled and the DPC list lock held on entry
  1555. ; to this routine. Control is returned to the caller with the same
  1556. ; conditions true.
  1557. ;
  1558. ; N.B. The registers ebx and ebp are preserved across the call.
  1559. ;
  1560. ; Arguments:
  1561. ;
  1562. ; ebx - Address of the target processor PCR.
  1563. ; ebp - Address of the target DPC listhead.
  1564. ;
  1565. ; Return value:
  1566. ;
  1567. ; None.
  1568. ;
  1569. ;--
  1570. if DBG
  1571. LOCAL_OFFSET equ 4
  1572. else
  1573. LOCAL_OFFSET equ 0
  1574. endif
  1575. public KiRetireDpcList
  1576. KiRetireDpcList proc
  1577. ?FpoValue = 0
  1578. ifndef NT_UP
  1579. ?FpoValue = 1
  1580. push esi ; save register
  1581. lea esi, [ebx].PcPrcbData.PbDpcLock ; get DPC lock address
  1582. endif
  1583. push 0 ; Used to indicate whether DPC event logging is on or off
  1584. sub esp, 12 ; space for saved DPC address and timestamp
  1585. cmp _PPerfGlobalGroupMask, 0 ; Is event tracing on?
  1586. jne rdl70 ; go check if DPC tracing is on
  1587. rdl3:
  1588. FPOFRAME ?FpoValue,0
  1589. rdl5: mov PCR[PcPrcbData.PbDpcRoutineActive], esp ; set DPC routine active
  1590. ;
  1591. ; Process the DPC List.
  1592. ;
  1593. rdl10: ;
  1594. ifndef NT_UP
  1595. ACQUIRE_SPINLOCK esi, rdl50, NoChecking ; acquire DPC lock
  1596. cmp ebp, [ebp].LsFlink ; check if DPC list is empty
  1597. je rdl45 ; if eq, DPC list is empty
  1598. endif
  1599. mov edx, [ebp].LsFlink ; get address of next entry
  1600. mov ecx, [edx].LsFlink ; get address of next entry
  1601. mov [ebp].LsFlink, ecx ; set address of next in header
  1602. mov [ecx].LsBlink, ebp ; set address of previous in next
  1603. sub edx, DpDpcListEntry ; compute address of DPC object
  1604. mov ecx, [edx].DpDeferredRoutine ; get DPC routine address
  1605. if DBG
  1606. push edi ; save register
  1607. mov edi, esp ; save current stack pointer
  1608. endif
  1609. FPOFRAME ?FpoValue,0
  1610. push [edx].DpSystemArgument2 ; second system argument
  1611. push [edx].DpSystemArgument1 ; first system argument
  1612. push [edx].DpDeferredContext ; get deferred context argument
  1613. push edx ; address of DPC object
  1614. mov dword ptr [edx]+DpLock, 0 ; clear DPC inserted state
  1615. dec dword ptr [ebx].PcPrcbData.PbDpcQueueDepth ; decrement depth
  1616. if DBG
  1617. mov PCR[PcPrcbData.PbDebugDpcTime], 0 ; Reset the time in DPC
  1618. endif
  1619. ifndef NT_UP
  1620. RELEASE_SPINLOCK esi, NoChecking ; release DPC lock
  1621. endif
  1622. sti ; enable interrupts
  1623. cmp [esp+LOCAL_OFFSET+28], 0 ; Are we doing event tracing?
  1624. jne rdl80
  1625. rdl20:
  1626. CAPSTART <KiRetireDpcList,ecx>
  1627. call ecx ; call DPC routine
  1628. CAPEND <KiRetireDpcList>
  1629. cmp [esp+LOCAL_OFFSET+12], 0 ; Are we doing event tracing?
  1630. jne rdl90
  1631. rdl25:
  1632. if DBG
  1633. stdCall _KeGetCurrentIrql ; get current IRQL
  1634. cmp al, DISPATCH_LEVEL ; check if still at dispatch level
  1635. jne rdl55 ; if ne, not at dispatch level
  1636. cmp esp, edi ; check if stack pointer is correct
  1637. jne rdl60 ; if ne, stack pointer is not correct
  1638. rdl30: pop edi ; restore register
  1639. endif
  1640. FPOFRAME ?FpoValue,0
  1641. rdl35: cli ; disable interrupts
  1642. cmp ebp, [ebp].LsFlink ; check if DPC list is empty
  1643. jne rdl10 ; if ne, DPC list not empty
  1644. ;
  1645. ; Clear DPC routine active and DPC requested flags.
  1646. ;
  1647. rdl40: mov [ebx].PcPrcbData.PbDpcRoutineActive, 0
  1648. mov [ebx].PcPrcbData.PbDpcInterruptRequested, 0
  1649. ;
  1650. ; Check one last time that the DPC list is empty. This is required to
  1651. ; close a race condition with the DPC queuing code where it appears that
  1652. ; a DPC routine is active (and thus an interrupt is not requested), but
  1653. ; this code has decided the DPC list is empty and is clearing the DPC
  1654. ; active flag.
  1655. ;
  1656. cmp ebp, [ebp].LsFlink ; check if DPC list is empty
  1657. jne rdl5 ; if ne, DPC list not empty
  1658. add esp, 16 ; pop locals
  1659. ifndef NT_UP
  1660. pop esi ; retore register
  1661. endif
  1662. ret ; return
  1663. ;
  1664. ; Unlock DPC list and clear DPC active.
  1665. ;
  1666. rdl45: ;
  1667. ifndef NT_UP
  1668. RELEASE_SPINLOCK esi, NoChecking ; release DPC lock
  1669. jmp short rdl40 ;
  1670. endif
  1671. ifndef NT_UP
  1672. rdl50: sti ; enable interrupts
  1673. SPIN_ON_SPINLOCK esi, <short rdl35> ; spin until lock is freee
  1674. endif
  1675. if DBG
  1676. rdl55: stdCall _KeBugCheckEx, <IRQL_NOT_GREATER_OR_EQUAL, ebx, eax, 0, 0> ;
  1677. rdl60: push dword ptr [edi+12] ; push address of DPC function
  1678. push offset FLAT:_MsgDpcTrashedEsp ; push message address
  1679. call _DbgPrint ; print debug message
  1680. add esp, 8 ; remove arguments from stack
  1681. int 3 ; break into debugger
  1682. mov esp, edi ; reset stack pointer
  1683. jmp rdl30 ;
  1684. endif
  1685. ;
  1686. ; Check if logging is on. If so, set logical on stack.
  1687. ;
  1688. rdl70:
  1689. mov eax, _PPerfGlobalGroupMask ; Load the ptr into eax
  1690. cmp eax, 0
  1691. jz rdl3
  1692. test dword ptr [eax+PERF_DPC_OFFSET], PERF_DPC_FLAG
  1693. jz rdl3 ; return if our flag is not set
  1694. mov [esp+12], 1 ; indicate DPC logging is on
  1695. jmp rdl3
  1696. ;
  1697. ; If logging DPC info, grab a timestamp to calculate the time in
  1698. ; the service routine.
  1699. ;
  1700. rdl80:
  1701. push ecx ; save DpcRoutine
  1702. PERF_GET_TIMESTAMP ; Places 64bit in edx:eax and trashes ecx
  1703. pop ecx
  1704. mov [esp+LOCAL_OFFSET+16], eax
  1705. mov [esp+LOCAL_OFFSET+20], edx
  1706. mov edx, [esp]
  1707. mov [esp+LOCAL_OFFSET+24], ecx ; Saves the service routine address
  1708. jmp rdl20
  1709. ;
  1710. ; Log the service routine and inital timestamp
  1711. ;
  1712. rdl90:
  1713. mov eax, [esp+LOCAL_OFFSET] ; pass the initial time
  1714. mov edx, [esp+LOCAL_OFFSET+4]
  1715. push edx
  1716. push eax
  1717. mov ecx, [esp+LOCAL_OFFSET+16] ; load saved service routine address
  1718. fstCall PerfInfoLogDpc
  1719. jmp rdl25
  1720. KiRetireDpcList endp
  1721. ifdef DBGMP
  1722. cPublicProc _KiPollDebugger,0
  1723. cPublicFpo 0,3
  1724. push eax
  1725. push ecx
  1726. push edx
  1727. POLL_DEBUGGER
  1728. pop edx
  1729. pop ecx
  1730. pop eax
  1731. stdRET _KiPollDebugger
  1732. stdENDP _KiPollDebugger
  1733. endif
  1734. page , 132
  1735. subttl "Adjust TSS ESP0 value"
  1736. ;++
  1737. ;
  1738. ; VOID
  1739. ; KiAdjustEsp0 (
  1740. ; IN PKTRAP_FRAME TrapFrame
  1741. ; )
  1742. ;
  1743. ; Routine Description:
  1744. ;
  1745. ; This routine puts the apropriate ESP0 value in the esp0 field of the
  1746. ; TSS. This allows protect mode and V86 mode to use the same stack
  1747. ; frame. The ESP0 value for protected mode is 16 bytes lower than
  1748. ; for V86 mode to compensate for the missing segment registers.
  1749. ;
  1750. ; Arguments:
  1751. ;
  1752. ; TrapFrame - Supplies a pointer to the TrapFrame.
  1753. ;
  1754. ; Return Value:
  1755. ;
  1756. ; None.
  1757. ;
  1758. ;--
  1759. cPublicProc _Ki386AdjustEsp0 ,1
  1760. stdCall ___KeGetCurrentThread
  1761. mov edx,[esp + 4] ; edx -> trap frame
  1762. mov eax,[eax]+thInitialStack ; eax = base of stack
  1763. test dword ptr [edx]+TsEFlags,EFLAGS_V86_MASK ; is this a V86 frame?
  1764. jnz short ae10
  1765. sub eax,TsV86Gs - TsHardwareSegSS ; compensate for missing regs
  1766. ae10: sub eax,NPX_FRAME_LENGTH
  1767. pushfd ; Make sure we don't move
  1768. cli ; processors while we do this
  1769. mov edx,PCR[PcTss]
  1770. mov [edx]+TssEsp0,eax ; set Esp0 value
  1771. popfd
  1772. stdRET _Ki386AdjustEsp0
  1773. stdENDP _Ki386AdjustEsp0
  1774. _TEXT$00 ends
  1775. end