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.

2132 lines
61 KiB

  1. //++
  2. //
  3. // Copyright (c) 1989-2000 Microsoft Corporation
  4. //
  5. // Component Name:
  6. //
  7. // NT / KE
  8. //
  9. // Module Name:
  10. //
  11. // ctxswap.s
  12. //
  13. // Abstract:
  14. //
  15. // This module implements the IA64 Process and Thread Context Swaps.
  16. //
  17. // Author:
  18. //
  19. // David N. Cutler (davec) 5-Mar-1989
  20. //
  21. // Environment:
  22. //
  23. // Kernel mode only
  24. //
  25. // Revision History:
  26. //
  27. // Bernard Lint Jul-12-1995
  28. //
  29. // Initial IA64 version
  30. //
  31. //--
  32. #include "ksia64.h"
  33. .file "ctxswap.s"
  34. .text
  35. //
  36. // Globals imported:
  37. //
  38. .global KiReadySummary
  39. .global KiIdleSummary
  40. .global KiDispatcherReadyListHead
  41. .global KeTickCount
  42. .global KiMasterSequence
  43. .global KiMasterRid
  44. .global PPerfGlobalGroupMask
  45. PublicFunction(KiDeliverApc)
  46. PublicFunction(KiSaveExceptionFrame)
  47. PublicFunction(KiRestoreExceptionFrame)
  48. PublicFunction(KiActivateWaiterQueue)
  49. PublicFunction(KiReadyThread)
  50. PublicFunction(KeFlushEntireTb)
  51. PublicFunction(KiQuantumEnd)
  52. PublicFunction(KiSyncNewRegionId)
  53. PublicFunction(KiCheckForSoftwareInterrupt)
  54. PublicFunction(KiSaveHigherFPVolatileAtDispatchLevel)
  55. PublicFunction(KeAcquireQueuedSpinLockAtDpcLevel)
  56. PublicFunction(KeReleaseQueuedSpinLockFromDpcLevel)
  57. PublicFunction(KeTryToAcquireQueuedSpinLockRaiseToSynch)
  58. PublicFunction(WmiTraceContextSwap)
  59. #if DBG
  60. PublicFunction(KeBugCheckEx)
  61. #endif // DBG
  62. SBTTL("Unlock Dispatcher Database")
  63. //++
  64. //--------------------------------------------------------------------
  65. //
  66. // VOID
  67. // KiUnlockDispatcherDatabase (
  68. // IN KIRQL OldIrql
  69. // )
  70. //
  71. // Routine Description:
  72. //
  73. // This routine is entered at synchronization level with the dispatcher
  74. // database locked. Its function is to either unlock the dispatcher
  75. // database and return or initiate a context switch if another thread
  76. // has been selected for execution.
  77. //
  78. // N.B. A context switch CANNOT be initiated if the previous IRQL
  79. // is greater than or equal to DISPATCH_LEVEL.
  80. //
  81. // N.B. This routine is carefully written to be a leaf function. If,
  82. // however, a context swap should be performed, the routine is
  83. // switched to a nested fucntion.
  84. //
  85. // Arguments:
  86. //
  87. // OldIrql (a0) - Supplies the IRQL when the dispatcher database
  88. // lock was acquired (in low order byte, not zero extended).
  89. //
  90. // Return Value:
  91. //
  92. // None.
  93. //
  94. //--------------------------------------------------------------------
  95. //--
  96. NESTED_ENTRY(KiUnlockDispatcherDatabase)
  97. NESTED_SETUP(1,3,1,0)
  98. //
  99. // Register aliases
  100. //
  101. rDPC = loc2 // DPC active flag
  102. rpT1 = t1 // temp pointer
  103. rpT2 = t2 // temp pointer
  104. rpT3 = t3 // temp pointer
  105. rT1 = t5 // temp regs
  106. rT2 = t6
  107. rPrcb = t8 // PRCB pointer
  108. pNotNl = pt2 // true if next thread not NULL
  109. pIRQGE = pt3 // true if DISPATCH_LEVEL <= old irql
  110. pIRQLT = pt4 // true if DISPATCH_LEVEL > old irql
  111. pDPC = pt5 // true if DPC active
  112. pNoAPC = pt2 // do not dispatch APC
  113. pAPC = pt9
  114. PROLOGUE_END
  115. //
  116. // Check if a thread has been scheduled to execute on the current processor
  117. //
  118. movl rPrcb = KiPcr + PcPrcb
  119. ;;
  120. LDPTR (rPrcb, rPrcb) // rPrcb -> PRCB
  121. ;;
  122. add rpT1 = PbNextThread, rPrcb // -> next thread
  123. add rpT2 = PbDpcRoutineActive,rPrcb // -> DPC active flag
  124. ;;
  125. LDPTR (v0, rpT1) // v0 = next thread
  126. ;;
  127. cmp.ne pNotNl = zero, v0 // pNotNl = next thread is 0
  128. zxt1 a0 = a0 // isolate old IRQL
  129. ;;
  130. (pNotNl) cmp.leu.unc pIRQGE, pIRQLT = DISPATCH_LEVEL, a0
  131. mov rDPC = 1 // speculate that DPC is active
  132. (pIRQLT) br.spnt KxUnlockDispatcherDatabase
  133. ;;
  134. //
  135. // Case 1:
  136. // Next thread is NULL:
  137. // Release dispatcher database lock, restore IRQL to its previous level
  138. // and return
  139. //
  140. //
  141. // Case 2:
  142. // A new thread has been selected to run on the current processor, but
  143. // the new IRQL is not below dispatch level. Release the dispatcher
  144. // lock and restore IRQL. If the current processor is
  145. // not executing a DPC, then request a dispatch interrupt on the current
  146. // processor.
  147. //
  148. // At this point pNotNl = 1 if thread not NULL, 0 if NULL
  149. //
  150. (pIRQGE) ld4 rDPC = [rpT2] // rDPC.4 = DPC active flag
  151. #if !defined(NT_UP)
  152. add out0 = (LockQueueDispatcherLock * 16) + PbLockQueue, rPrcb
  153. br.call.sptk brp = KeReleaseQueuedSpinLockFromDpcLevel
  154. #endif // !defined(NT_UP)
  155. ;;
  156. LOWER_IRQL(a0)
  157. cmp4.eq pDPC = rDPC, zero // pDPC = request DPC intr
  158. REQUEST_DISPATCH_INT(pDPC) // request DPC interrupt
  159. NESTED_RETURN
  160. NESTED_EXIT(KiUnlockDispatcherDatabase)
  161. //
  162. // N.B. This routine is carefully written as a nested function.
  163. // Control only reaches this routine from above.
  164. //
  165. // rPrcb contains the address of PRCB
  166. // v0 contains the next thread
  167. //
  168. NESTED_ENTRY(KxUnlockDispatcherDatabase)
  169. PROLOGUE_BEGIN
  170. .regstk 1, 2, 1, 0
  171. alloc t16 = ar.pfs, 1, 2, 1, 0
  172. .save rp, loc0
  173. mov loc0 = brp
  174. .fframe SwitchFrameLength
  175. add sp = -SwitchFrameLength, sp
  176. ;;
  177. .save ar.unat, loc1
  178. mov loc1 = ar.unat
  179. add t0 = ExFltS19+SwExFrame+STACK_SCRATCH_AREA, sp
  180. add t1 = ExFltS18+SwExFrame+STACK_SCRATCH_AREA, sp
  181. ;;
  182. .save.gf 0x0, 0xC0000
  183. stf.spill [t0] = fs19, ExFltS17-ExFltS19
  184. stf.spill [t1] = fs18, ExFltS16-ExFltS18
  185. ;;
  186. .save.gf 0x0, 0x30000
  187. stf.spill [t0] = fs17, ExFltS15-ExFltS17
  188. stf.spill [t1] = fs16, ExFltS14-ExFltS16
  189. mov t10 = bs4
  190. ;;
  191. .save.gf 0x0, 0xC000
  192. stf.spill [t0] = fs15, ExFltS13-ExFltS15
  193. stf.spill [t1] = fs14, ExFltS12-ExFltS14
  194. mov t11 = bs3
  195. ;;
  196. .save.gf 0x0, 0x3000
  197. stf.spill [t0] = fs13, ExFltS11-ExFltS13
  198. stf.spill [t1] = fs12, ExFltS10-ExFltS12
  199. mov t12 = bs2
  200. ;;
  201. .save.gf 0x0, 0xC00
  202. stf.spill [t0] = fs11, ExFltS9-ExFltS11
  203. stf.spill [t1] = fs10, ExFltS8-ExFltS10
  204. mov t13 = bs1
  205. ;;
  206. .save.gf 0x0, 0x300
  207. stf.spill [t0] = fs9, ExFltS7-ExFltS9
  208. stf.spill [t1] = fs8, ExFltS6-ExFltS8
  209. mov t14 = bs0
  210. ;;
  211. .save.gf 0x0, 0xC0
  212. stf.spill [t0] = fs7, ExFltS5-ExFltS7
  213. stf.spill [t1] = fs6, ExFltS4-ExFltS6
  214. mov t15 = ar.lc
  215. ;;
  216. .save.gf 0x0, 0x30
  217. stf.spill [t0] = fs5, ExFltS3-ExFltS5
  218. stf.spill [t1] = fs4, ExFltS2-ExFltS4
  219. ;;
  220. .save.f 0xC
  221. stf.spill [t0] = fs3, ExFltS1-ExFltS3 // save fs3
  222. stf.spill [t1] = fs2, ExFltS0-ExFltS2 // save fs2
  223. ;;
  224. .save.f 0x3
  225. stf.spill [t0] = fs1, ExBrS4-ExFltS1 // save fs1
  226. stf.spill [t1] = fs0, ExBrS3-ExFltS0 // save fs0
  227. ;;
  228. .save.b 0x18
  229. st8 [t0] = t10, ExBrS2-ExBrS4 // save bs4
  230. st8 [t1] = t11, ExBrS1-ExBrS3 // save bs3
  231. ;;
  232. .save.b 0x6
  233. st8 [t0] = t12, ExBrS0-ExBrS2 // save bs2
  234. st8 [t1] = t13, ExIntS2-ExBrS1 // save bs1
  235. ;;
  236. .save.b 0x1
  237. st8 [t0] = t14, ExIntS3-ExBrS0 // save bs0
  238. movl t12 = KiPcr + PcCurrentThread
  239. ;;
  240. .save.gf 0xC, 0x0
  241. .mem.offset 0,0
  242. st8.spill [t0] = s3, ExIntS1-ExIntS3 // save s3
  243. .mem.offset 8,0
  244. st8.spill [t1] = s2, ExIntS0-ExIntS2 // save s2
  245. ;;
  246. .save.gf 0x3, 0x0
  247. .mem.offset 0,0
  248. st8.spill [t0] = s1, ExApLC-ExIntS1 // save s1
  249. .mem.offset 8,0
  250. st8.spill [t1] = s0, ExApEC-ExIntS0 // save s0
  251. ;;
  252. .savepsp ar.pfs, ExceptionFrameLength-ExApEC-STACK_SCRATCH_AREA
  253. st8 [t1] = t16, ExIntNats-ExApEC
  254. mov t4 = ar.unat // captured Nats of s0-s3
  255. mov s0 = rPrcb
  256. LDPTR (s1, t12) // current thread
  257. ;;
  258. .savepsp ar.lc, ExceptionFrameLength-ExApLC-STACK_SCRATCH_AREA
  259. st8 [t0] = t15
  260. .savepsp @priunat, ExceptionFrameLength-ExIntNats-STACK_SCRATCH_AREA
  261. st8 [t1] = t4 // save Nats of s0-s3
  262. mov s2 = v0
  263. PROLOGUE_END
  264. add rpT2 = PbNextThread, s0 // -> next thread
  265. add out0 = ThWaitIrql, s1 // -> previous IRQL
  266. ;;
  267. STPTRINC (rpT2, zero,PbCurrentThread-PbNextThread) // clear NextThread
  268. st1 [out0] = a0, ThIdleSwapBlock-ThWaitIrql // save old IRQL
  269. mov rpT3 = 1
  270. ;;
  271. //
  272. // Reready current thread for execution and swap context to the selected
  273. // thread.
  274. //
  275. // Note: Set IdleSwapBlock in the current thread so no idle processor
  276. // can switch to this processor before it is removed from the current
  277. // processor.
  278. STPTR (rpT2, s2) // set current thread object
  279. st1 [out0] = rpT3, -ThIdleSwapBlock// out0 -> previous thread
  280. br.call.sptk brp = KiReadyThread
  281. ;;
  282. br.call.sptk brp = SwapContext
  283. ;;
  284. //
  285. // Lower IRQL, deallocate exception/switch frame.
  286. //
  287. // N.B. SwapContext releases the dispatcher database lock.
  288. //
  289. // N.B. v0 contains the kernel APC pending state on return.
  290. //
  291. // N.B. s2 contains the address of the new thread on return.
  292. //
  293. add rpT2 = ThWaitIrql, s2 // -> ThWaitIrql
  294. cmp.ne pAPC, pNoAPC = zero, v0
  295. ;;
  296. ld1 a0 = [rpT2] // a0 = original wait IRQL
  297. ;;
  298. (pAPC) cmp.ne pNoAPC = zero, a0 // APC pending and IRQL == 0
  299. (pNoAPC) br.spnt Kudd_Exit
  300. ;;
  301. .regstk 1, 2, 3, 0
  302. alloc t16 = ar.pfs, 1, 2, 3, 0
  303. mov rT2 = APC_LEVEL
  304. ;;
  305. SET_IRQL(rT2)
  306. mov out0 = KernelMode
  307. mov out1 = zero
  308. mov out2 = zero
  309. br.call.sptk brp = KiDeliverApc
  310. ;;
  311. //
  312. // Lower IRQL to wait level, set return status, restore registers, and return.
  313. //
  314. Kudd_Exit:
  315. LOWER_IRQL(a0) // a0 = new irql
  316. add out0 = STACK_SCRATCH_AREA+SwExFrame, sp
  317. br.call.sptk brp = KiRestoreExceptionFrame
  318. ;;
  319. add rpT1 = ExApEC+SwExFrame+STACK_SCRATCH_AREA, sp
  320. ;;
  321. ld8 rT1 = [rpT1]
  322. mov brp = loc0
  323. ;;
  324. mov ar.unat = loc1
  325. nop.f 0
  326. mov ar.pfs = rT1
  327. .restore
  328. add sp = SwitchFrameLength, sp
  329. nop.i 0
  330. br.ret.sptk brp
  331. ;;
  332. NESTED_EXIT(KxUnlockDispatcherDatabase)
  333. SBTTL("Swap Thread")
  334. //++
  335. //--------------------------------------------------------------------
  336. //
  337. // BOOLEAN
  338. // KiSwapContext (
  339. // IN PKTHREAD Thread
  340. // )
  341. //
  342. // Routine Description:
  343. //
  344. // This routine saves the non-volatile registers, marshals the
  345. // arguments for SwapContext and calls SwapContext to perform
  346. // the actual thread switch.
  347. //
  348. // Arguments:
  349. //
  350. // Thread - Supplies the address of the new thread.
  351. //
  352. // Return Value:
  353. //
  354. // If a kernel APC is pending, then a value of TRUE is returned.
  355. // Otherwise, FALSE is returned.
  356. //
  357. // Notes:
  358. //
  359. // GP valid on entry -- GP is not switched, just use kernel GP
  360. //--------------------------------------------------------------------
  361. //--
  362. NESTED_ENTRY(KiSwapContext)
  363. //
  364. // Register aliases
  365. //
  366. pNoAPC = pt2 // do not dispatch APC
  367. rpT1 = t0 // temp pointer
  368. rpT2 = t1 // temp pointer
  369. rT1 = t10 // temp regs
  370. PROLOGUE_BEGIN
  371. .regstk 1, 2, 1, 0
  372. alloc t16 = ar.pfs, 1, 2, 1, 0
  373. .save rp, loc0
  374. mov loc0 = brp
  375. .fframe SwitchFrameLength
  376. add sp = -SwitchFrameLength, sp
  377. ;;
  378. .save ar.unat, loc1
  379. mov loc1 = ar.unat
  380. add t0 = ExFltS19+SwExFrame+STACK_SCRATCH_AREA, sp
  381. add t1 = ExFltS18+SwExFrame+STACK_SCRATCH_AREA, sp
  382. ;;
  383. .save.gf 0x0, 0xC0000
  384. stf.spill [t0] = fs19, ExFltS17-ExFltS19
  385. stf.spill [t1] = fs18, ExFltS16-ExFltS18
  386. ;;
  387. .save.gf 0x0, 0x30000
  388. stf.spill [t0] = fs17, ExFltS15-ExFltS17
  389. stf.spill [t1] = fs16, ExFltS14-ExFltS16
  390. mov t10 = bs4
  391. ;;
  392. .save.gf 0x0, 0xC000
  393. stf.spill [t0] = fs15, ExFltS13-ExFltS15
  394. stf.spill [t1] = fs14, ExFltS12-ExFltS14
  395. mov t11 = bs3
  396. ;;
  397. .save.gf 0x0, 0x3000
  398. stf.spill [t0] = fs13, ExFltS11-ExFltS13
  399. stf.spill [t1] = fs12, ExFltS10-ExFltS12
  400. mov t12 = bs2
  401. ;;
  402. .save.gf 0x0, 0xC00
  403. stf.spill [t0] = fs11, ExFltS9-ExFltS11
  404. stf.spill [t1] = fs10, ExFltS8-ExFltS10
  405. mov t13 = bs1
  406. ;;
  407. .save.gf 0x0, 0x300
  408. stf.spill [t0] = fs9, ExFltS7-ExFltS9
  409. stf.spill [t1] = fs8, ExFltS6-ExFltS8
  410. mov t14 = bs0
  411. ;;
  412. .save.gf 0x0, 0xC0
  413. stf.spill [t0] = fs7, ExFltS5-ExFltS7
  414. stf.spill [t1] = fs6, ExFltS4-ExFltS6
  415. mov t15 = ar.lc
  416. ;;
  417. .save.gf 0x0, 0x30
  418. stf.spill [t0] = fs5, ExFltS3-ExFltS5
  419. stf.spill [t1] = fs4, ExFltS2-ExFltS4
  420. ;;
  421. .save.f 0xC
  422. stf.spill [t0] = fs3, ExFltS1-ExFltS3 // save fs3
  423. stf.spill [t1] = fs2, ExFltS0-ExFltS2 // save fs2
  424. ;;
  425. .save.f 0x3
  426. stf.spill [t0] = fs1, ExBrS4-ExFltS1 // save fs1
  427. stf.spill [t1] = fs0, ExBrS3-ExFltS0 // save fs0
  428. ;;
  429. .save.b 0x18
  430. st8 [t0] = t10, ExBrS2-ExBrS4 // save bs4
  431. st8 [t1] = t11, ExBrS1-ExBrS3 // save bs3
  432. ;;
  433. .save.b 0x6
  434. st8 [t0] = t12, ExBrS0-ExBrS2 // save bs2
  435. st8 [t1] = t13, ExIntS2-ExBrS1 // save bs1
  436. ;;
  437. .save.b 0x1
  438. st8 [t0] = t14, ExIntS3-ExBrS0 // save bs0
  439. ;;
  440. .save.gf 0xC, 0x0
  441. .mem.offset 0,0
  442. st8.spill [t0] = s3, ExIntS1-ExIntS3 // save s3
  443. .mem.offset 8,0
  444. st8.spill [t1] = s2, ExIntS0-ExIntS2 // save s2
  445. ;;
  446. .save.gf 0x3, 0x0
  447. .mem.offset 0,0
  448. st8.spill [t0] = s1, ExApLC-ExIntS1 // save s1
  449. .mem.offset 8,0
  450. st8.spill [t1] = s0, ExApEC-ExIntS0 // save s0
  451. ;;
  452. .savepsp ar.pfs, ExceptionFrameLength-ExApEC-STACK_SCRATCH_AREA
  453. st8 [t1] = t16, ExIntNats-ExApEC
  454. mov t4 = ar.unat // captured Nats of s0-s3
  455. ;;
  456. .savepsp ar.lc, ExceptionFrameLength-ExApLC-STACK_SCRATCH_AREA
  457. st8 [t0] = t15
  458. .savepsp @priunat, ExceptionFrameLength-ExIntNats-STACK_SCRATCH_AREA
  459. st8 [t1] = t4 // save Nats of s0-s3
  460. PROLOGUE_END
  461. //
  462. // For the call to SwapContext-
  463. //
  464. // s0 // Prcb address
  465. // s1 // old thread address
  466. // s2 // new thread address
  467. // pt0 = 1
  468. //
  469. mov s2 = a0 // s2 <- New Thread
  470. movl rpT1 = KiPcr + PcPrcb
  471. ;;
  472. LDPTRINC (s0, rpT1, PcCurrentThread-PcPrcb)// s0 <- Prcb
  473. ;;
  474. LDPTR (s1, rpT1) // s1 <- Old Thread
  475. add rpT2 = PbCurrentThread, s0
  476. ;;
  477. //
  478. // Swap context to the next thread.
  479. //
  480. STPTR (rpT2, a0) // Set new thread current
  481. cmp.eq pt0 = zero, zero // indicate lock context swap
  482. br.call.sptk brp = SwapContext // call SwapContext(prcb, OldTh, NewTh)
  483. ;;
  484. //
  485. // Deallocate exception/switch frame.
  486. //
  487. // N.B. SwapContext releases the dispatcher database lock.
  488. //
  489. // N.B. v0 contains the kernel APC pending state on return, ie, 0 if
  490. // no APC pending, 1 if APC pending. v0 will be forced to 0 if
  491. // the new IRQL doesn't allow APCs.
  492. //
  493. // N.B. KiRestoreExceptionFrame doesn't touch v0, t21 or t22.
  494. //
  495. add rpT2 = ThWaitIrql, s2 // -> ThWaitIrql
  496. add rpT1 = ExApEC+SwExFrame+STACK_SCRATCH_AREA, sp
  497. add out0 = STACK_SCRATCH_AREA+SwExFrame, sp
  498. ;;
  499. ld1 t21 = [rpT2] // t21 = original wait IRQL
  500. ld8 t22 = [rpT1] // t22 = PFS
  501. br.call.sptk brp = KiRestoreExceptionFrame
  502. ;;
  503. mov brp = loc0
  504. cmp.ne pNoAPC = zero, t21 // no APC if IRQL != 0
  505. ;;
  506. mov ar.unat = loc1
  507. nop.f 0
  508. mov ar.pfs = t22
  509. .restore
  510. add sp = SwitchFrameLength, sp
  511. (pNoAPC) mov v0 = zero
  512. br.ret.sptk brp
  513. ;;
  514. NESTED_EXIT(KiSwapContext)
  515. SBTTL("Swap Context to Next Thread")
  516. //++
  517. //--------------------------------------------------------------------
  518. // Routine:
  519. //
  520. // SwapContext
  521. //
  522. // Routine Description:
  523. //
  524. // This routine is called to swap context from one thread to the next.
  525. //
  526. // Arguments:
  527. //
  528. // s0 - Address of Processor Control Block (PRCB).
  529. // s1 - Address of previous thread object.
  530. // s2 - Address of next thread object.
  531. //
  532. // Return value:
  533. //
  534. // v0 - Kernel APC pending flag
  535. // s0 - Address of Processor Control Block (PRCB).
  536. // s1 - Address of previous thread object.
  537. // s2 - Address of current thread object.
  538. //
  539. // Note:
  540. // Kernel GP is not saved and restored across context switch
  541. //
  542. // !!WARNING!! - Thierry. 03/01/2000.
  543. // Be aware that this implementation is a result of performance analysis.
  544. // Please consider this when you are making changes...
  545. //
  546. //--------------------------------------------------------------------
  547. //--
  548. NESTED_ENTRY(SwapContext)
  549. //
  550. // Register aliases
  551. //
  552. rT1 = t1 // temp
  553. rT2 = t2 // temp
  554. rT3 = t3 // temp
  555. rNewproc = t4 // next process object
  556. rOldproc = t5 // previous process object
  557. rpThBSL = t6 // pointer to new thread backing store limit
  558. rpT1 = t7 // temp pointer
  559. rpT2 = t8 // temp pointer
  560. rpT3 = t9 // temp pointer
  561. rAr1 = t10
  562. rAr2 = t11
  563. rAr3 = t12
  564. rAr4 = t13
  565. rNewIKS = t14 // new initial kernel stack
  566. rNewKSL = t15 // new kernel stack limit
  567. rNewBSP = t16 // new thread BSP/BSPSTORE
  568. rOldBSP = t16 // old thread BSP
  569. rOldRNAT = t17 // old thread RNAT
  570. rNewRNAT = t17 // new thread RNAT
  571. rOldSbase = t18 // old thread kstack base
  572. pUsTh = pt4 // is user thread?
  573. pKrTh = pt5 // is user thread?
  574. pSave = pt7 // is high fp set dirty?
  575. pDiff = ps4 // if new and old process different
  576. pSame = ps5 // if new and old process same
  577. //
  578. // Set new thread's state to running. Note this must be done
  579. // under the dispatcher lock so that KiSetPriorityThread sees
  580. // the correct state.
  581. //
  582. PROLOGUE_BEGIN
  583. #if !defined(NT_UP)
  584. alloc rT2 = ar.pfs, 0, 0, 4, 0
  585. mov rT1 = brp // move from brp takes 2 cycles
  586. add rpT3 = ThState, s2
  587. ;;
  588. lfetch.excl [rpT3]
  589. mov rAr1 = Running
  590. add rpT2 = SwPFS+STACK_SCRATCH_AREA, sp
  591. ;;
  592. add out0 = (LockQueueContextSwapLock * 16) + PbLockQueue, s0
  593. .savesp ar.pfs, SwPFS+STACK_SCRATCH_AREA
  594. st8.nta [rpT2] = rT2, SwRp-SwPFS // save pfs
  595. ;;
  596. .savesp brp, SwRp+STACK_SCRATCH_AREA
  597. st8.nta [rpT2] = rT1 // save return link
  598. st1.nta [rpT3] = rAr1 // set thread state to Running
  599. br.call.sptk brp = KeAcquireQueuedSpinLockAtDpcLevel
  600. ;;
  601. //
  602. // Release DispatcherLock.
  603. //
  604. add out0 = (LockQueueDispatcherLock * 16) + PbLockQueue, s0
  605. br.call.sptk brp = KeReleaseQueuedSpinLockFromDpcLevel
  606. ;;
  607. mov out0 = ar.fpsr // move from ar.fpsr takes 12 cycles
  608. movl rpT1 = KiPcr+PcHighFpOwner // setup for prefetching
  609. ;;
  610. { .mmi
  611. lfetch [rpT1]
  612. cmp.ne pUsTh = zero, teb // test for ia32 save required
  613. // must not have a nop.f for next 10 cycles--
  614. // Using temporarely the explicit templating
  615. // for the next cycles.
  616. add out1 = ThStackBase, s1 // move early to start access for rOldSbase
  617. { .mmi
  618. add rpT1 = SwFPSR+STACK_SCRATCH_AREA, sp
  619. add rpT2 = SwPreds+STACK_SCRATCH_AREA, sp
  620. nop.i 0x0
  621. }
  622. ;;
  623. { .mmi
  624. ld8.nta rOldSbase = [out1] // speculative start early for ia32 saves
  625. lfetch.excl [rpT1]
  626. add out2 = ThNumber, s2 // setup for prefetching
  627. }
  628. { .mmi
  629. mov.m ar.rsc = r0 // put RSE in lazy mode
  630. mov rOldBSP = ar.bsp // move from ar.bsp takes 12 cycles
  631. nop.i 0x0
  632. }
  633. ;;
  634. { .mmi
  635. lfetch [out2]
  636. nop.m 0x0
  637. mov rT1 = pr // move from pr takes 2 cycles
  638. }
  639. ;;
  640. { .mmi
  641. flushrs
  642. mov rT3 = psr.um // move from psr.um takes 12 cycles
  643. nop.i 0x0
  644. }
  645. ;;
  646. { .mmi
  647. lfetch.excl [rpT2]
  648. mov.m rOldRNAT = ar.rnat // move from ar.rnat takes 5 cycles
  649. add out2 = @gprel(PPerfGlobalGroupMask), gp
  650. }
  651. ;;
  652. { .mli
  653. lfetch [out2]
  654. movl out3 = KiPcr + PcInterruptionCount // INTERRUPTION_LOGGING on or off, we are prefetching this line.
  655. // If any real performance problem is detected, we will undef these lines.
  656. }
  657. ;;
  658. { .mmi
  659. lfetch [out3]
  660. add rpT3 = SwRnat+STACK_SCRATCH_AREA, sp
  661. }
  662. ;;
  663. #else // NT_UP
  664. alloc rT2 = ar.pfs, 0, 0, 4, 0
  665. cmp.ne pUsTh = zero, teb // test for ia32 save required
  666. ;;
  667. mov.m ar.rsc = r0 // put RSE in lazy mode
  668. add out1 = ThStackBase, s1 // move early to start access for rOldSbase
  669. mov out0 = ar.fpsr // move from ar.fpsr takes 12 cycles
  670. // must not have a nop.f for next 10 cycles--
  671. // Using temporarely the explicit templating
  672. // for the next cycles.
  673. ;;
  674. { .mmi
  675. ld8.nta rOldSbase = [out1] // speculative start early for ia32 saves
  676. mov rOldBSP = ar.bsp // move from ar.bsp takes 12 cycles
  677. add rpT1 = SwRp+STACK_SCRATCH_AREA, sp
  678. }
  679. ;;
  680. flushrs
  681. mov rT3 = psr.um // move from psr.um takes 12 cycles
  682. add rpT2 = SwPFS+STACK_SCRATCH_AREA, sp
  683. ;;
  684. mov.m rOldRNAT = ar.rnat // move from ar.rnat takes 5 cycles
  685. mov rT1 = brp // move from brp takes 2 cycles
  686. add rpT3 = ThState, s2
  687. ;;
  688. { .mmi
  689. mov rAr1 = Running
  690. .savesp brp, SwRp+STACK_SCRATCH_AREA
  691. st8.nta [rpT1] = rT1, SwFPSR-SwRp // save return link
  692. nop.i 0x0
  693. }
  694. ;;
  695. { .mii
  696. st1.nta [rpT3] = rAr1 // set thread state to Running
  697. mov rT1 = pr // move from pr takes 2 cycles
  698. nop.i 0x0
  699. }
  700. ;;
  701. { .mii
  702. .savesp ar.pfs, SwPFS+STACK_SCRATCH_AREA
  703. st8.nta [rpT2] = rT2, SwPreds-SwPFS // save pfs
  704. add rpT3 = SwRnat+STACK_SCRATCH_AREA, sp
  705. nop.i 0x0
  706. }
  707. ;;
  708. #endif // NT_UP
  709. { .mmi
  710. st8.nta [rpT3] = rOldRNAT
  711. nop.m 0x0
  712. nop.i 0x0
  713. }
  714. st8 [rpT1] = out0, SwBsp-SwFPSR // save kernel FPSR
  715. st8 [rpT2] = rT1 // save preserved predicates
  716. ;;
  717. st8.nta [rpT1] = rOldBSP
  718. add rpT3 = ThKernelBStore, s1
  719. tbit.nz pSave = rT3, PSR_MFH // check mfh bit
  720. (pUsTh) br.call.spnt brp = SwapContextIA32Save
  721. ;;
  722. st8.nta [rpT3] = rOldBSP
  723. (pSave) add out0 = -ThreadStateSaveAreaLength+TsHigherFPVolatile, rOldSbase
  724. (pSave) br.call.spnt brp = KiSaveHigherFPVolatileAtDispatchLevel
  725. ;;
  726. //
  727. // Acquire the context swap lock so the address space of the old process
  728. // cannot be deleted and then release the dispatcher database lock.
  729. //
  730. // N.B. This lock is used to protect the address space until the context
  731. // switch has sufficiently progressed to the point where the address
  732. // space is no longer needed. This lock is also acquired by the reaper
  733. // thread before it finishes thread termination.
  734. //
  735. PROLOGUE_END
  736. //
  737. // ***** TBD ****** Save performance counters? (user vs. kernel)
  738. //
  739. //
  740. // Accumlate the total time spent in a thread.
  741. //
  742. #if defined(PERF_DATA)
  743. **** TBD **** MIPS code
  744. addu a0,sp,ExFltF20 // compute address of result
  745. move a1,zero // set address of optional frequency
  746. jal KeQueryPerformanceCounter // query performance counter
  747. lw t0,ExFltF20(sp) // get current cycle count
  748. lw t1,ExFltF20 + 4(sp) //
  749. lw t2,PbStartCount(s0) // get starting cycle count
  750. lw t3,PbStartCount + 4(s0) //
  751. sw t0,PbStartCount(s0) // set starting cycle count
  752. sw t1,PbStartCount + 4(s0) //
  753. lw t4,EtPerformanceCountLow(s1) // get accumulated cycle count
  754. lw t5,EtPerformanceCountHigh(s1) //
  755. subu t6,t0,t2 // subtract low parts
  756. subu t7,t1,t3 // subtract high parts
  757. sltu v0,t0,t2 // generate borrow from high part
  758. subu t7,t7,v0 // subtract borrow
  759. addu t6,t6,t4 // add low parts
  760. addu t7,t7,t5 // add high parts
  761. sltu v0,t6,t4 // generate carry into high part
  762. addu t7,t7,v0 // add carry
  763. sw t6,EtPerformanceCountLow(s1) // set accumulated cycle count
  764. sw t7,EtPerformanceCountHigh(s1) //
  765. #endif // defined(PERF_DATA)
  766. //
  767. // The following entry point is used to switch from the idle thread to
  768. // another thread.
  769. //
  770. ;;
  771. ALTERNATE_ENTRY(SwapFromIdle)
  772. alloc rT1 = ar.pfs, 2, 0, 2, 0
  773. //
  774. // Check if we are tracing context swaps
  775. //
  776. mov out0 = s1 // assign out0 to old ethread pointer
  777. add rpT3 = @gprel(PPerfGlobalGroupMask), gp
  778. ;;
  779. ld8.nta rpT3 = [rpT3] // get value of PperfGlobalGroupMask
  780. mov out1 = s2 // assign out1 to new ethread pointer
  781. ;;
  782. add rpT2 = PERF_CONTEXTSWAP_OFFSET, rpT3
  783. cmp.ne pt3 = zero, rpT3 // if it's non-zero, then trace on
  784. ;;
  785. (pt3) ld4.nta rpT2 = [rpT2]
  786. ;;
  787. (pt3) and rpT2 = PERF_CONTEXTSWAP_FLAG, rpT2
  788. ;;
  789. (pt3) cmp.ne.unc pt4 = zero, rpT2
  790. (pt4) br.call.spnt brp = WmiTraceContextSwap // optimize for no tracing case
  791. ;;
  792. //
  793. // Get address of old and new process objects.
  794. //
  795. add rpT2 = ThApcState+AsProcess,s2 // -> new thread AsProcess
  796. add rpT1 = ThApcState+AsProcess,s1 // -> old thread AsProcess
  797. ;;
  798. LDPTR (rOldproc, rpT1) // old process
  799. LDPTR (rNewproc, rpT2) // new process
  800. #if !defined(NT_UP)
  801. //
  802. // In MP system,
  803. // should a thread address is recycled and the thread is migrated to a
  804. // processor that holds the stale values in the high fp register set,
  805. // set KiPcr->HighFpOwner to zero (i.e. when pt4 is set to TRUE)
  806. //
  807. add rpT1 = ThNumber, s2
  808. movl rpT2 = KiPcr+PcHighFpOwner
  809. ;;
  810. ld1 rT1 = [rpT1]
  811. ld8 rT2 = [rpT2], PcNumber-PcHighFpOwner
  812. add out0 = ThIdleSwapBlock, s1
  813. ;;
  814. ld1 rT3 = [rpT2], PcHighFpOwner-PcNumber
  815. st1 [out0] = zero // clear OldThread->IdleSwapBlock
  816. cmp.eq pt3 = rT2, s2
  817. ;;
  818. (pt3) cmp.ne.unc pt4 = rT1, rT3
  819. ;;
  820. (pt4) st8 [rpT2] = zero
  821. #endif // !defined(NT_UP)
  822. ;;
  823. flushrs
  824. FAST_DISABLE_INTERRUPTS
  825. ;;
  826. //
  827. // Thierry - 03/29/2000
  828. // It should be noticed that the performance analysis for SwapContext
  829. // was done with INTERRUPTION_LOGGING defined as 1.
  830. //
  831. #define INTERRUPTION_LOGGING 1
  832. #if defined(INTERRUPTION_LOGGING)
  833. // For Conditional Interrupt Logging
  834. #define ContextSwitchBit 63
  835. .global KiVectorLogMask
  836. mov rT3 = gp
  837. ;;
  838. movl gp = _gp
  839. ;;
  840. add rpT1 = @gprel(KiVectorLogMask), gp
  841. ;;
  842. ld8 rT1 = [rpT1]
  843. mov gp = rT3
  844. ;;
  845. tbit.z pt4 = rT1, ContextSwitchBit
  846. (pt4) br.cond.sptk EndOfLogging0
  847. movl rpT1 = KiPcr+PcInterruptionCount
  848. mov rT3 = MAX_NUMBER_OF_IHISTORY_RECORDS - 1
  849. cmp.ne pDiff,pSame=rOldproc,rNewproc
  850. ;;
  851. (pDiff) mov rT1 = 0x91 // process switch
  852. ld4.nt1 rT2 = [rpT1] // get current count
  853. ;;
  854. (pSame) mov rT1 = 0x90 // thread switch
  855. add rpT3 = 1, rT2 // incr count
  856. and rT2 = rT3, rT2 // index of current entry
  857. add rpT2 = 0x1000-PcInterruptionCount, rpT1 // base of history
  858. ;;
  859. st4.nta [rpT1] = rpT3 // save count
  860. shl rT2 = rT2, 5 // offset of current entry
  861. ;;
  862. add rpT2 = rpT2, rT2 // address of current entry
  863. ;;
  864. st8 [rpT2] = rT1, 8 // save switch type
  865. ;;
  866. st8 [rpT2] = s2, 8 // save new thread pointer
  867. ;;
  868. st8 [rpT2] = s1, 8 // save old thread
  869. ;;
  870. st8 [rpT2] = sp // save old sp
  871. ;;
  872. // For Conditional Interrupt Logging
  873. EndOfLogging0:
  874. #endif // INTERRUPTION_LOGGING
  875. mov ar.rsc = r0 // put RSE in lazy mode
  876. add rpT1 = ThInitialStack, s2
  877. add rpT2 = ThKernelStack, s1
  878. ;;
  879. //
  880. // Store the kernel stack pointer in the previous thread object,
  881. // load the new kernel stack pointer from the new thread object,
  882. // switch backing store pointers, select new process id and swap
  883. // to the new process.
  884. //
  885. ld8.nta rNewIKS = [rpT1], ThKernelStack-ThInitialStack
  886. st8.nta [rpT2] = sp // save current sp
  887. ;;
  888. ld8.nta sp = [rpT1], ThStackLimit-ThKernelStack
  889. movl rpT2 = KiPcr + PcInitialStack
  890. ;;
  891. alloc rT1 = 0,0,0,0 // make current frame 0 size
  892. ld8.nta rNewKSL = [rpT1], ThInitialBStore-ThStackLimit
  893. ;;
  894. loadrs // invalidate RSE and ALAT
  895. ld8.nta rT1 = [rpT1], ThBStoreLimit-ThInitialBStore
  896. ;;
  897. ld8.nta rT2 = [rpT1], ThDebugActive-ThBStoreLimit
  898. st8 [rpT2] = rNewIKS, PcStackLimit-PcInitialStack
  899. ;;
  900. // get debugger active state
  901. ld1.nta rT3 = [rpT1], ThTeb-ThDebugActive
  902. st8 [rpT2] = rNewKSL, PcInitialBStore-PcStackLimit
  903. add rpT3 = SwBsp+STACK_SCRATCH_AREA, sp
  904. ;;
  905. ld8 rNewBSP = [rpT3], SwRnat-SwBsp
  906. st8 [rpT2] = rT1, PcBStoreLimit-PcInitialBStore
  907. ;;
  908. ld8 rNewRNAT = [rpT3]
  909. st8 [rpT2] = rT2, PcDebugActive-PcBStoreLimit
  910. ;;
  911. // load new teb
  912. ld8 teb = [rpT1], ThApcState+AsKernelApcPending-ThTeb
  913. // set new debugger active state
  914. st1 [rpT2] = rT3, PcCurrentThread-PcDebugActive
  915. invala
  916. //
  917. // Setup PCR intial kernel BSP and BSTORE limit
  918. //
  919. mov ar.bspstore = rNewBSP // load new bspstore
  920. cmp.ne pDiff,pSame=rOldproc,rNewproc // if ne, switch process
  921. ;;
  922. mov ar.rnat = rNewRNAT // load new RNATs
  923. ;;
  924. mov ar.rsc = RSC_KERNEL // enable RSE
  925. ;;
  926. //
  927. // If the new process is not the same as the old process, then swap the
  928. // address space to the new process.
  929. //
  930. // N.B. The context swap lock cannot be dropped until all references to the
  931. // old process address space are complete. This includes any possible
  932. // TB Misses that could occur referencing the new address space while
  933. // still executing in the old address space.
  934. //
  935. // N.B. The process address space swap is executed with interrupts disabled.
  936. //
  937. alloc rT1 = 0,4,2,0
  938. STPTR (rpT2, s2)
  939. ;;
  940. mov kteb = teb // update kernel TEB
  941. FAST_ENABLE_INTERRUPTS
  942. ld1 loc0 = [rpT1] // load the ApcPending flag
  943. #if !defined(NT_UP)
  944. //
  945. // Release the context swap lock
  946. // N.B. ContextSwapLock is always released in KxSwapProcess, if called
  947. //
  948. add out0 = (LockQueueContextSwapLock * 16) + PbLockQueue, s0
  949. add loc1 = PcApcInterrupt-PcCurrentThread, rpT2
  950. (pSame) br.call.sptk brp = KeReleaseQueuedSpinLockFromDpcLevel
  951. ;;
  952. #else // !defined(NT_UP)
  953. add loc1 = PcApcInterrupt-PcCurrentThread, rpT2
  954. ;;
  955. #endif // !defined(NT_UP)
  956. mov out0 = rNewproc // set address of new process
  957. mov out1 = rOldproc // set address of old process
  958. (pDiff) br.call.sptk brp = KxSwapProcess // call swap address space(NewProc, OldProc)
  959. ;;
  960. //
  961. // In new address space, if changed.
  962. //
  963. st1 [loc1] = loc0 // request (or clear) APC pend.
  964. add rpT1 = PbContextSwitches, s0
  965. add rpT2 = ThContextSwitches, s2
  966. ;;
  967. //
  968. // If the new thread has a kernel mode APC pending, then request an APC
  969. // interrupt.
  970. //
  971. ld4 loc1 = [rpT1]
  972. ld4 loc2 = [rpT2]
  973. ;;
  974. //
  975. // Increment context switch counters
  976. //
  977. cmp.ne pUsTh, pKrTh = zero, teb
  978. add loc1 = loc1, zero, 1
  979. add loc2 = loc2, zero, 1
  980. ;;
  981. st4 [rpT1] = loc1 // increment # of context switches
  982. st4 [rpT2] = loc2 // increment # of context switches
  983. add rpT1 = SwFPSR+STACK_SCRATCH_AREA, sp
  984. add rpT2 = SwPFS+STACK_SCRATCH_AREA, sp
  985. ;;
  986. ld8 loc1 = [rpT1], SwRp-SwFPSR // restore brp and pfs
  987. ld8 loc2 = [rpT2], SwPreds-SwPFS
  988. ;;
  989. ld8 rT3 = [rpT1]
  990. ld8 rT2 = [rpT2]
  991. mov v0 = loc0 // set v0 = apc pending
  992. (pUsTh) br.call.spnt brp = SwapContextIA32Restore
  993. ;;
  994. //
  995. // Note: at this point s0 = Prcb, s1 = previous thread, s2 = current thread
  996. //
  997. mov ar.fpsr = loc1
  998. mov ar.pfs = loc2
  999. mov brp = rT3
  1000. mov pr = rT2 // Restore preserved preds
  1001. #if 0
  1002. //
  1003. // Thierry 03/22/2000:
  1004. //
  1005. // The following memory synchronization of the local processor
  1006. // I-cache and D-cache because of I-stream modifications is not
  1007. // required if the modifying code is written following the NT
  1008. // Core Team specifications:
  1009. // - [Allocate VA]
  1010. // - Modify the code
  1011. // - Call FlushIntructionCache()
  1012. // -> calls KiSweepIcache[Range]()
  1013. // - Execute the code.
  1014. //
  1015. // The removal of this instruction eliminates a "> 100 cycle" stall.
  1016. //
  1017. sync.i
  1018. #endif // 0
  1019. ;;
  1020. srlz.i
  1021. br.ret.sptk brp
  1022. NESTED_EXIT(SwapContext)
  1023. //++
  1024. //--------------------------------------------------------------------
  1025. // Routine:
  1026. //
  1027. // SwapContextIA32Save
  1028. //
  1029. // Routine Description:
  1030. //
  1031. // This function saves the IA32 context on the kernel stack.
  1032. // Called from SwapContext.
  1033. //
  1034. // Arguments:
  1035. //
  1036. // rOldSbase : old thread kstack base.
  1037. //
  1038. // Return value:
  1039. //
  1040. // None.
  1041. //
  1042. // Note:
  1043. //
  1044. // SwapContext registers context.
  1045. //
  1046. //--------------------------------------------------------------------
  1047. //--
  1048. LEAF_ENTRY(SwapContextIA32Save)
  1049. mov rAr1 = ar21 // IA32 FP control register FCR
  1050. ;;
  1051. mov rAr2 = ar24 // IA32 EFLAG register
  1052. ;;
  1053. mov rAr3 = ar25
  1054. ;;
  1055. mov rAr4 = ar26
  1056. ;;
  1057. //
  1058. // we may skip saving ar27 because it cannot be modified by user code
  1059. //
  1060. mov rT1 = ar30
  1061. ;;
  1062. mov rT2 = ar28
  1063. ;;
  1064. mov rT3 = ar29
  1065. ;;
  1066. // these are separated out due to cache miss potential
  1067. add rpT1 = -ThreadStateSaveAreaLength+TsAppRegisters+TsAr21, rOldSbase
  1068. add rpT2 = -ThreadStateSaveAreaLength+TsAppRegisters+TsAr24, rOldSbase
  1069. ;;
  1070. st8 [rpT1] = rAr1, TsAr25-TsAr21
  1071. st8 [rpT2] = rAr2, TsAr26-TsAr24
  1072. ;;
  1073. st8 [rpT1] = rAr3, TsAr29-TsAr25
  1074. st8 [rpT2] = rAr4, TsAr28-TsAr26
  1075. ;;
  1076. st8 [rpT2] = rT2, TsAr30-TsAr28
  1077. ;;
  1078. st8 [rpT2] = rT1
  1079. st8 [rpT1] = rT3
  1080. br.ret.sptk.few.clr brp
  1081. LEAF_EXIT(SwapContextIA32Save)
  1082. //++
  1083. //--------------------------------------------------------------------
  1084. // Routine:
  1085. //
  1086. // SwapContextIA32Restore
  1087. //
  1088. // Routine Description:
  1089. //
  1090. // This function restores the IA32 registers context.
  1091. // Called from SwapContext.
  1092. //
  1093. // Arguments:
  1094. //
  1095. // s2 - Address of next thread object.
  1096. //
  1097. // Return value:
  1098. //
  1099. // None.
  1100. //
  1101. // Note:
  1102. //
  1103. // SwapContext registers context.
  1104. //
  1105. //--------------------------------------------------------------------
  1106. //--
  1107. LEAF_ENTRY(SwapContextIA32Restore)
  1108. add rpT1 = ThStackBase, s2
  1109. ;;
  1110. ld8.nta rpT1 = [rpT1]
  1111. ;;
  1112. add rpT2 = -ThreadStateSaveAreaLength+TsAppRegisters+TsAr21, rpT1
  1113. add rpT3 = -ThreadStateSaveAreaLength+TsAppRegisters+TsAr24, rpT1
  1114. ;;
  1115. ld8.nta rAr1 = [rpT2], TsAr25-TsAr21
  1116. ld8.nta rAr2 = [rpT3], TsAr26-TsAr24
  1117. ;;
  1118. ld8.nta rAr3 = [rpT2], TsAr27-TsAr25
  1119. ld8.nta rAr4 = [rpT3], TsAr28-TsAr26
  1120. ;;
  1121. mov ar21 = rAr1
  1122. mov ar24 = rAr2
  1123. mov ar25 = rAr3
  1124. mov ar26 = rAr4
  1125. ld8.nta rAr1 = [rpT2], TsAr29-TsAr27
  1126. ld8.nta rAr2 = [rpT3], TsAr30-TsAr28
  1127. ;;
  1128. ld8.nta rAr3 = [rpT2]
  1129. ld8.nta rAr4 = [rpT3]
  1130. ;;
  1131. mov ar27 = rAr1
  1132. mov ar28 = rAr2
  1133. mov ar29 = rAr3
  1134. mov ar30 = rAr4
  1135. br.ret.sptk.few.clr brp
  1136. LEAF_EXIT(SwapContextIA32Restore)
  1137. SBTTL("Swap Process")
  1138. //++
  1139. //--------------------------------------------------------------------
  1140. //
  1141. // VOID
  1142. // KiSwapProcess (
  1143. // IN PKPROCESS NewProcess,
  1144. // IN PKPROCESS OldProcess
  1145. // )
  1146. //
  1147. // Routine Description:
  1148. //
  1149. // This function swaps the address space from one process to another by
  1150. // assigning a new region id, if necessary, and loading the fixed entry
  1151. // in the TB that maps the process page directory page. This routine follows
  1152. // the PowerPC design for handling RID wrap.
  1153. //
  1154. // On entry/exit:
  1155. //
  1156. // Interrupt enabled.
  1157. //
  1158. // Arguments:
  1159. //
  1160. // NewProcess (a0) - Supplies a pointer to a control object of type process
  1161. // which represents the new process that is switched to (32-bit address).
  1162. //
  1163. // OldProcess (a1) - Supplies a pointer to a control object of type process
  1164. // which represents the old process that is switched from (32-bit address).
  1165. //
  1166. // Return Value:
  1167. //
  1168. // None.
  1169. //
  1170. //--------------------------------------------------------------------
  1171. //--
  1172. NESTED_ENTRY(KiSwapProcess)
  1173. NESTED_SETUP(2,3,3,0)
  1174. PROLOGUE_END
  1175. //
  1176. // Register aliases
  1177. //
  1178. rNewProc = a0
  1179. rOldProc = a1
  1180. rpCSLock = loc2
  1181. rpT1 = t0
  1182. rpT2 = t1
  1183. rProcSet = t2
  1184. rNewActive= t3
  1185. rOldActive= t4
  1186. rMasterSeq= t5
  1187. rNewSeq = t6
  1188. rOldPsrL = t7
  1189. rVa = t8
  1190. rPDE0 = t9 // PDE for page directory page 0
  1191. rVa2 = t10
  1192. rSessionBase = t11
  1193. rSessionInfo = t12
  1194. rT1 = t13
  1195. rT2 = t14
  1196. //
  1197. // KiSwapProcess must get the context swap lock
  1198. // KxSwapProcess is called from SwapContext with the lock held
  1199. //
  1200. #if !defined(NT_UP)
  1201. movl rpT1 = KiPcr+PcPrcb
  1202. ;;
  1203. ld8 rpT1 = [rpT1]
  1204. ;;
  1205. add out0 = (LockQueueContextSwapLock * 16) + PbLockQueue, rpT1
  1206. br.call.sptk brp = KeAcquireQueuedSpinLockAtDpcLevel
  1207. ;;
  1208. br.sptk Ksp_Continue
  1209. #endif // !defined(NT_UP)
  1210. ;;
  1211. ALTERNATE_ENTRY(KxSwapProcess)
  1212. NESTED_SETUP(2,3,3,0)
  1213. PROLOGUE_END
  1214. //
  1215. // Clear the processor set member number in the old process and set the
  1216. // processor member number in the new process.
  1217. //
  1218. Ksp_Continue:
  1219. #if !defined(NT_UP)
  1220. add rpT2 = PrActiveProcessors, rOldProc // -> old active processor set
  1221. movl rpT1 = KiPcr + PcSetMember // -> processor set member
  1222. ;;
  1223. ld4 rProcSet= [rpT1] // rProcSet.4 = processor set member
  1224. add rpT1 = PrActiveProcessors, rNewProc // -> new active processor set
  1225. ;;
  1226. ld4 rNewActive = [rpT1] // rNewActive.4 = new active processor set
  1227. ld4 rOldActive = [rpT2] // rOldActive.4 = old active processor set
  1228. ;;
  1229. or rNewActive = rNewActive,rProcSet // set processor member in new set
  1230. xor rOldActive = rOldActive,rProcSet // clear processor member in old set
  1231. ;;
  1232. st4 [rpT1] = rNewActive // set new active processor set
  1233. st4 [rpT2] = rOldActive // set old active processor set
  1234. #endif // !defined(NT_UP)
  1235. //
  1236. // If the process sequence number matches the system sequence number, then
  1237. // use the process RID. Otherwise, allocate a new process RID.
  1238. //
  1239. // N.B. KiMasterRid, KiMasterSequence are changed only when holding the
  1240. // KiContextSwapLock.
  1241. //
  1242. add rT2 = PrSessionMapInfo, rNewProc
  1243. add out0 = PrProcessRegion, rNewProc
  1244. ;;
  1245. ld8 out1 = [rT2]
  1246. br.call.sptk brp = KiSyncNewRegionId
  1247. ;;
  1248. //
  1249. // Switch address space to new process
  1250. // v0 = rRid = new process rid
  1251. //
  1252. fwb // hint to flush write buffers
  1253. FAST_DISABLE_INTERRUPTS
  1254. add rpT1 = PrDirectoryTableBase, rNewProc
  1255. movl rVa = KiPcr+PcPdeUtbase
  1256. add rpT2 = PrSessionParentBase, rNewProc
  1257. movl rVa2 = KiPcr+PcPdeStbase
  1258. ;;
  1259. ld8.nta rPDE0 = [rpT1] // rPDE0 = Page directory page 0
  1260. ld8.nta rSessionBase = [rpT2]
  1261. ld8.nta rVa = [rVa]
  1262. ld8.nta rVa2 = [rVa2]
  1263. ;;
  1264. //
  1265. // To access IFA, ITDR registers, PSR.ic bit must be 0. Otherwise,
  1266. // it causes an illegal operation fault. While PSR.ic=0, any
  1267. // interruption can not be afforded. Make sure there will be no
  1268. // TLB miss and no interrupt coming in during this period.
  1269. //
  1270. rsm 1 << PSR_IC // PSR.ic=0
  1271. ;;
  1272. srlz.d // must serialize
  1273. mov rT1 = PAGE_SHIFT << IDTR_PS // load page size field for IDTR
  1274. ;;
  1275. mov cr.itir = rT1 // set up IDTR for dirbase
  1276. ptr.d rVa, rT1 // remove DTR for user space
  1277. ;;
  1278. mov cr.ifa = rVa // set up IFA for dirbase vaddr
  1279. mov rT2 = DTR_UTBASE_INDEX
  1280. ;;
  1281. itr.d dtr[rT2] = rPDE0 // insert PDE0 to DTR
  1282. ;;
  1283. ptr.d rVa2, rT1 // remove DTR for session
  1284. ;; // to avoid a overlapping error
  1285. mov cr.ifa = rVa2
  1286. mov rT2 = DTR_STBASE_INDEX
  1287. ;;
  1288. itr.d dtr[rT2] = rSessionBase // insert the root for session space
  1289. ;;
  1290. ssm 1 << PSR_IC // PSR.ic=1
  1291. ;;
  1292. srlz.i // must I serialize
  1293. #if DBG
  1294. mov t0 = PbProcessorState+KpsSpecialRegisters+KsTrD0+(8*DTR_UTBASE_INDEX)
  1295. movl t3 = KiPcr + PcPrcb
  1296. ;;
  1297. ld8 t3 = [t3]
  1298. mov t1 = PbProcessorState+KpsSpecialRegisters+KsTrD0+(8*DTR_STBASE_INDEX)
  1299. ;;
  1300. add t0 = t3, t0
  1301. add t1 = t3, t1
  1302. ;;
  1303. st8 [t0] = rPDE0
  1304. st8 [t1] = rSessionBase
  1305. ;;
  1306. #endif
  1307. FAST_ENABLE_INTERRUPTS
  1308. //
  1309. // Now make sure branch history is enabled for non wow processes
  1310. // and disabled for wow processes
  1311. //
  1312. add t1 = @gprel(KiVectorLogMask), gp
  1313. ;;
  1314. ld8 t1 = [t1]
  1315. ;;
  1316. cmp.eq pt0 = t1, r0
  1317. (pt0) br.cond.sptk SkipBranchHistory
  1318. mov t1 = 3
  1319. ;;
  1320. mov t2 = cpuid[t1]
  1321. add t3 = PrWow64Process, rNewProc
  1322. ;;
  1323. extr.u t2 = t2, 24, 8
  1324. ld4 t4 = [t3];
  1325. ;;
  1326. cmp.ne pt1 = 7, t2
  1327. ;;
  1328. mov t1 = 675
  1329. (pt1) br.dpnt SkipBranchHistory
  1330. ;;
  1331. mov t2 = msr[t1]
  1332. cmp.eq pt1,pt2 = zero, t4 // Wow64 is non-zero
  1333. ;;
  1334. (pt1) mov t3 = 2 // Enable the HB for ia64 procs
  1335. (pt2) mov t3 = 256 // Disable the HB for wow64 procs
  1336. ;;
  1337. dep t2 = t3, t2, 0, 9 // Disable the HB for wow64 procs
  1338. ;;
  1339. mov msr[t1] = t2;
  1340. ;;
  1341. SkipBranchHistory:
  1342. #if !defined(NT_UP)
  1343. //
  1344. // Can now release the context swap lock
  1345. //
  1346. movl rpT1 = KiPcr+PcPrcb
  1347. ;;
  1348. ld8 rpT1 = [rpT1]
  1349. ;;
  1350. add out0 = (LockQueueContextSwapLock * 16) + PbLockQueue, rpT1
  1351. br.call.sptk brp = KeReleaseQueuedSpinLockFromDpcLevel
  1352. ;;
  1353. #endif // !defined(NT_UP)
  1354. NESTED_RETURN
  1355. NESTED_EXIT(KiSwapProcess)
  1356. SBTTL("Retire Deferred Procedure Call List")
  1357. //++
  1358. // Routine:
  1359. //
  1360. // VOID
  1361. // KiRetireDpcList (
  1362. // PKPRCB Prcb,
  1363. // )
  1364. //
  1365. // Routine Description:
  1366. //
  1367. // This routine is called to retire the specified deferred procedure
  1368. // call list. DPC routines are called using the idle thread (current)
  1369. // stack.
  1370. //
  1371. // N.B. Interrupts must be disabled on entry to this routine. Control is returned
  1372. // to the caller with the same conditions true.
  1373. //
  1374. // Arguments:
  1375. //
  1376. // a0 - Address of the current PRCB.
  1377. //
  1378. // Return value:
  1379. //
  1380. // None.
  1381. //
  1382. //--
  1383. NESTED_ENTRY(KiRetireDpcList)
  1384. NESTED_SETUP(1,2,4,0)
  1385. PROLOGUE_END
  1386. Krdl_Restart:
  1387. add t0 = PbDpcQueueDepth, a0
  1388. add t1 = PbDpcRoutineActive, a0
  1389. add t2 = PbDpcLock, a0
  1390. ;;
  1391. ld4 t4 = [t0]
  1392. add t3 = PbDpcListHead+LsFlink, a0
  1393. ;;
  1394. Krdl_Restart2:
  1395. cmp4.eq pt1 = zero, t4
  1396. st4 [t1] = t4
  1397. (pt1) br.spnt Krdl_Exit
  1398. ;;
  1399. #if !defined(NT_UP)
  1400. ACQUIRE_SPINLOCK(t2, a0, Krdl_20)
  1401. #endif // !defined(NT_UP)
  1402. ld4 t4 = [t0]
  1403. LDPTR (t5, t3) // -> first DPC entry
  1404. ;;
  1405. cmp4.eq pt1, pt2 = zero, t4
  1406. ;;
  1407. (pt2) add t10 = LsFlink, t5
  1408. (pt2) add out0 = -DpDpcListEntry, t5
  1409. (pt1) br.spnt Krdl_Unlock
  1410. ;;
  1411. LDPTR (t6, t10)
  1412. add t11 = DpDeferredRoutine, out0
  1413. add t12 = DpSystemArgument1, out0
  1414. ;;
  1415. //
  1416. // Setup call to DPC routine
  1417. //
  1418. // arguments are:
  1419. // dpc object address (out0)
  1420. // deferred context (out1)
  1421. // system argument 1 (out2)
  1422. // system argument 2 (out3)
  1423. //
  1424. // N.B. the arguments must be loaded from the DPC object BEFORE
  1425. // the inserted flag is cleared to prevent the object being
  1426. // overwritten before its time.
  1427. //
  1428. ld8.nt1 t13 = [t11], DpDeferredContext-DpDeferredRoutine
  1429. ld8.nt1 out2 = [t12], DpSystemArgument2-DpSystemArgument1
  1430. ;;
  1431. ld8.nt1 out1 = [t11], DpLock-DpDeferredContext
  1432. ld8.nt1 out3 = [t12]
  1433. add t4 = -1, t4
  1434. STPTRINC (t3, t6, -LsFlink)
  1435. ld8.nt1 t14 = [t13], 8
  1436. add t15 = LsBlink, t6
  1437. ;;
  1438. ld8.nt1 gp = [t13]
  1439. STPTR (t15, t3)
  1440. STPTR (t11, zero)
  1441. st4 [t0] = t4
  1442. #if !defined(NT_UP)
  1443. RELEASE_SPINLOCK(t2) // set spin lock not owned
  1444. #endif //!defined(NT_UP)
  1445. FAST_ENABLE_INTERRUPTS
  1446. mov bt0 = t14
  1447. br.call.sptk.few.clr brp = bt0 // call DPC routine
  1448. ;;
  1449. //
  1450. // Check to determine if any more DPCs are available to process.
  1451. //
  1452. FAST_DISABLE_INTERRUPTS
  1453. br Krdl_Restart
  1454. ;;
  1455. //
  1456. // The DPC list became empty while we were acquiring the DPC queue lock.
  1457. // Clear DPC routine active. The race condition mentioned above doesn't
  1458. // exist here because we hold the DPC queue lock.
  1459. //
  1460. Krdl_Unlock:
  1461. #if !defined(NT_UP)
  1462. add t2 = PbDpcLock, a0
  1463. ;;
  1464. RELEASE_SPINLOCK(t2)
  1465. #endif // !defined(NT_UP)
  1466. Krdl_Exit:
  1467. add t0 = PbDpcQueueDepth, a0
  1468. add t1 = PbDpcRoutineActive, a0
  1469. add out0 = PbDpcInterruptRequested, a0
  1470. ;;
  1471. st4.nta [t1] = zero
  1472. st4.rel.nta [out0] = zero
  1473. add t2 = PbDpcLock, a0
  1474. ld4 t4 = [t0]
  1475. add t3 = PbDpcListHead+LsFlink, a0
  1476. ;;
  1477. cmp4.eq pt1, pt2 = zero, t4
  1478. (pt2) br.spnt Krdl_Restart2
  1479. ;;
  1480. NESTED_RETURN
  1481. NESTED_EXIT(KiRetireDpcList)
  1482. SBTTL("Dispatch Interrupt")
  1483. //++
  1484. //--------------------------------------------------------------------
  1485. // Routine:
  1486. //
  1487. // KiDispatchInterrupt
  1488. //
  1489. // Routine Description:
  1490. //
  1491. // This routine is entered as the result of a software interrupt generated
  1492. // at DISPATCH_LEVEL. Its function is to process the Deferred Procedure Call
  1493. // (DPC) list, and then perform a context switch if a new thread has been
  1494. // selected for execution on the processor.
  1495. //
  1496. // This routine is entered at IRQL DISPATCH_LEVEL with the dispatcher
  1497. // database unlocked. When a return to the caller finally occurs, the
  1498. // IRQL remains at DISPATCH_LEVEL, and the dispatcher database is still
  1499. // unlocked.
  1500. //
  1501. // N.B. On entry to this routine the volatile states (excluding high
  1502. // floating point register set) have been saved.
  1503. //
  1504. // On entry:
  1505. //
  1506. // sp - points to stack scratch area.
  1507. //
  1508. // Arguments:
  1509. //
  1510. // None
  1511. //
  1512. // Return Value:
  1513. //
  1514. // None.
  1515. //--------------------------------------------------------------------
  1516. //--
  1517. NESTED_ENTRY(KiDispatchInterrupt)
  1518. PROLOGUE_BEGIN
  1519. .regstk 0, 4, 2, 0
  1520. alloc t16 = ar.pfs, 0, 4, 2, 0
  1521. .save rp, loc0
  1522. mov loc0 = brp
  1523. .fframe SwitchFrameLength
  1524. add sp = -SwitchFrameLength, sp
  1525. ;;
  1526. .save ar.unat, loc1
  1527. mov loc1 = ar.unat
  1528. add t0 = ExFltS19+SwExFrame+STACK_SCRATCH_AREA, sp
  1529. add t1 = ExFltS18+SwExFrame+STACK_SCRATCH_AREA, sp
  1530. ;;
  1531. .save.gf 0x0, 0xC0000
  1532. stf.spill [t0] = fs19, ExFltS17-ExFltS19
  1533. stf.spill [t1] = fs18, ExFltS16-ExFltS18
  1534. ;;
  1535. .save.gf 0x0, 0x30000
  1536. stf.spill [t0] = fs17, ExFltS15-ExFltS17
  1537. stf.spill [t1] = fs16, ExFltS14-ExFltS16
  1538. mov t10 = bs4
  1539. ;;
  1540. .save.gf 0x0, 0xC000
  1541. stf.spill [t0] = fs15, ExFltS13-ExFltS15
  1542. stf.spill [t1] = fs14, ExFltS12-ExFltS14
  1543. mov t11 = bs3
  1544. ;;
  1545. .save.gf 0x0, 0x3000
  1546. stf.spill [t0] = fs13, ExFltS11-ExFltS13
  1547. stf.spill [t1] = fs12, ExFltS10-ExFltS12
  1548. mov t12 = bs2
  1549. ;;
  1550. .save.gf 0x0, 0xC00
  1551. stf.spill [t0] = fs11, ExFltS9-ExFltS11
  1552. stf.spill [t1] = fs10, ExFltS8-ExFltS10
  1553. mov t13 = bs1
  1554. ;;
  1555. .save.gf 0x0, 0x300
  1556. stf.spill [t0] = fs9, ExFltS7-ExFltS9
  1557. stf.spill [t1] = fs8, ExFltS6-ExFltS8
  1558. mov t14 = bs0
  1559. ;;
  1560. .save.gf 0x0, 0xC0
  1561. stf.spill [t0] = fs7, ExFltS5-ExFltS7
  1562. stf.spill [t1] = fs6, ExFltS4-ExFltS6
  1563. mov t15 = ar.lc
  1564. ;;
  1565. .save.gf 0x0, 0x30
  1566. stf.spill [t0] = fs5, ExFltS3-ExFltS5
  1567. stf.spill [t1] = fs4, ExFltS2-ExFltS4
  1568. ;;
  1569. .save.f 0xC
  1570. stf.spill [t0] = fs3, ExFltS1-ExFltS3 // save fs3
  1571. stf.spill [t1] = fs2, ExFltS0-ExFltS2 // save fs2
  1572. ;;
  1573. .save.f 0x3
  1574. stf.spill [t0] = fs1, ExBrS4-ExFltS1 // save fs1
  1575. stf.spill [t1] = fs0, ExBrS3-ExFltS0 // save fs0
  1576. ;;
  1577. .save.b 0x18
  1578. st8 [t0] = t10, ExBrS2-ExBrS4 // save bs4
  1579. st8 [t1] = t11, ExBrS1-ExBrS3 // save bs3
  1580. ;;
  1581. .save.b 0x6
  1582. st8 [t0] = t12, ExBrS0-ExBrS2 // save bs2
  1583. st8 [t1] = t13, ExIntS2-ExBrS1 // save bs1
  1584. ;;
  1585. .save.b 0x1
  1586. st8 [t0] = t14, ExIntS3-ExBrS0 // save bs0
  1587. ;;
  1588. .save.gf 0xC, 0x0
  1589. .mem.offset 0,0
  1590. st8.spill [t0] = s3, ExIntS1-ExIntS3 // save s3
  1591. .mem.offset 8,0
  1592. st8.spill [t1] = s2, ExIntS0-ExIntS2 // save s2
  1593. ;;
  1594. .save.gf 0x3, 0x0
  1595. .mem.offset 0,0
  1596. st8.spill [t0] = s1, ExApLC-ExIntS1 // save s1
  1597. .mem.offset 8,0
  1598. st8.spill [t1] = s0, ExApEC-ExIntS0 // save s0
  1599. ;;
  1600. .savepsp ar.pfs, ExceptionFrameLength-ExApEC-STACK_SCRATCH_AREA
  1601. st8 [t1] = t16, ExIntNats-ExApEC
  1602. mov t4 = ar.unat // captured Nats of s0-s3
  1603. ;;
  1604. .savepsp ar.lc, ExceptionFrameLength-ExApLC-STACK_SCRATCH_AREA
  1605. st8 [t0] = t15
  1606. .savepsp @priunat, ExceptionFrameLength-ExIntNats-STACK_SCRATCH_AREA
  1607. st8 [t1] = t4 // save Nats of s0-s3
  1608. PROLOGUE_END
  1609. //
  1610. // Register aliases
  1611. //
  1612. rPrcb = loc2
  1613. rKerGP = loc3
  1614. rpT1 = t0
  1615. rpT2 = t1
  1616. rT1 = t2
  1617. rT2 = t3
  1618. rpDPLock = t4 // pointer to dispatcher lock
  1619. pNoTh = pt1 // No next thread to run
  1620. pNext = pt2 // next thread not null
  1621. pNull = pt3 // no thread available
  1622. pOwned = pt4 // dispatcher lock already owned
  1623. pNotOwned = pt5
  1624. pQEnd = pt6 // quantum end request pending
  1625. pNoQEnd = pt7 // no quantum end request pending
  1626. //
  1627. // Increment the dispatch interrupt count
  1628. //
  1629. mov rKerGP = gp // save gp
  1630. movl rPrcb = KiPcr + PcPrcb
  1631. ;;
  1632. LDPTR (rPrcb, rPrcb) // rPrcb -> Prcb
  1633. ;;
  1634. add rpT1 = PbDispatchInterruptCount, rPrcb
  1635. ;;
  1636. ld4 rT1 = [rpT1]
  1637. ;;
  1638. add rT1 = rT1, zero, 1
  1639. ;;
  1640. st4 [rpT1] = rT1
  1641. // **** TBD **** use alpha optimization to first check Dpc Q depth
  1642. //
  1643. // Process the DPC list
  1644. //
  1645. Kdi_PollDpcList:
  1646. //
  1647. // Process the deferred procedure call list.
  1648. //
  1649. FAST_ENABLE_INTERRUPTS
  1650. ;;
  1651. srlz.d
  1652. //
  1653. // **** TBD ***** No stack switch as in alpha, mips...
  1654. // Save current initial stack address and set new initial stack address.
  1655. //
  1656. FAST_DISABLE_INTERRUPTS
  1657. mov out0 = rPrcb
  1658. br.call.sptk brp = KiRetireDpcList
  1659. ;;
  1660. //
  1661. // Check to determine if quantum end has occured.
  1662. //
  1663. // N.B. If a new thread is selected as a result of processing a quantum
  1664. // end request, then the new thread is returned with the dispatcher
  1665. // database locked. Otherwise, NULL is returned with the dispatcher
  1666. // database unlocked.
  1667. //
  1668. FAST_ENABLE_INTERRUPTS
  1669. add rpT1 = PbQuantumEnd, rPrcb
  1670. ;;
  1671. ld4 rT1 = [rpT1] // get quantum end indicator
  1672. ;;
  1673. cmp4.ne pQEnd, pNoQEnd = rT1, zero // if zero, no quantum end reqs
  1674. mov gp = rKerGP // restore gp
  1675. ;;
  1676. (pQEnd) st4 [rpT1] = zero // clear quantum end indicator
  1677. (pNoQEnd) br.cond.sptk Kdi_NoQuantumEnd
  1678. (pQEnd) br.call.spnt brp = KiQuantumEnd // call KiQuantumEnd (C code)
  1679. ;;
  1680. cmp4.eq pNoTh, pNext = v0, zero // pNoTh = no next thread
  1681. (pNoTh) br.dpnt Kdi_Exit // br to exit if no next thread
  1682. (pNext) br.dpnt Kdi_Swap // br to swap to next thread
  1683. //
  1684. // If no quantum end requests:
  1685. // Check to determine if a new thread has been selected for execution on
  1686. // this processor.
  1687. //
  1688. Kdi_NoQuantumEnd:
  1689. add rpT2 = PbNextThread, rPrcb
  1690. ;;
  1691. LDPTR (rT1, rpT2) // rT1 = address of next thread object
  1692. ;;
  1693. cmp.eq pNull = rT1, zero // pNull => no thread selected
  1694. (pNull) br.dpnt Kdi_Exit // exit if no thread selected
  1695. #if !defined(NT_UP)
  1696. //
  1697. // try to acquire the dispatcher database lock.
  1698. //
  1699. mov out0 = LockQueueDispatcherLock
  1700. movl out1 = KiPcr+PcSystemReserved+8
  1701. br.call.sptk brp = KeTryToAcquireQueuedSpinLockRaiseToSynch
  1702. ;;
  1703. cmp.ne pOwned, pNotOwned = TRUE, v0 // pOwned = 1 if not free
  1704. (pOwned) br.dpnt Kdi_PollDpcList // br out if owned
  1705. ;;
  1706. #else
  1707. mov rT1 = SYNCH_LEVEL
  1708. ;;
  1709. SET_IRQL (rT1)
  1710. #endif // !defined(NT_UP)
  1711. //
  1712. // Reread address of next thread object since it is possible for it to
  1713. // change in a multiprocessor system.
  1714. //
  1715. Kdi_Swap:
  1716. add rpT2 = PbNextThread, rPrcb // -> next thread
  1717. movl rpT1 = KiPcr + PcCurrentThread
  1718. ;;
  1719. LDPTR (s1, rpT1) // current thread object
  1720. LDPTR (s2, rpT2) // next thread object
  1721. add rpT1 = PbCurrentThread, rPrcb
  1722. ;;
  1723. //
  1724. // Reready current thread for execution and swap context to the selected
  1725. // thread.
  1726. //
  1727. // Note: Set IdleSwapBlock in the current thread so no idle processor
  1728. // can switch to this processor before it is removed from the current
  1729. // processor.
  1730. //
  1731. STPTR (rpT2, zero) // clear addr of next thread
  1732. add out0 = ThIdleSwapBlock, s1 // block swap from idle
  1733. mov rT1 = 1
  1734. ;;
  1735. STPTR (rpT1, s2) // set addr of current thread
  1736. st1 [out0] = rT1, -ThIdleSwapBlock// set addr of previous thread
  1737. br.call.sptk brp = KiReadyThread // call KiReadyThread(OldTh)
  1738. ;;
  1739. mov s0 = rPrcb // setup call
  1740. cmp.ne pt0 = zero, zero // no need to lock context swap
  1741. br.call.sptk brp = SwapContext // call SwapContext(Prcb, OldTh, NewTh)
  1742. ;;
  1743. //
  1744. // Restore saved registers, and return.
  1745. //
  1746. add out0 = STACK_SCRATCH_AREA+SwExFrame, sp
  1747. br.call.sptk brp = KiRestoreExceptionFrame
  1748. ;;
  1749. Kdi_Exit:
  1750. add rpT1 = ExApEC+SwExFrame+STACK_SCRATCH_AREA, sp
  1751. ;;
  1752. ld8 rT1 = [rpT1]
  1753. mov brp = loc0
  1754. ;;
  1755. mov ar.unat = loc1
  1756. mov ar.pfs = rT1
  1757. .restore
  1758. add sp = SwitchFrameLength, sp
  1759. br.ret.sptk brp
  1760. NESTED_EXIT(KiDispatchInterrupt)