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.

1248 lines
44 KiB

  1. // TITLE("Context Swap")
  2. //++
  3. //
  4. // Copyright (c) 1991 Microsoft Corporation
  5. // Copyright (c) 1992 Digital Equipment Corporation
  6. //
  7. // Module Name:
  8. //
  9. // ctxsw.s
  10. //
  11. // Abstract:
  12. //
  13. // This module implements the ALPHA machine dependent code necessary to
  14. // field the dispatch interrupt and to perform kernel initiated context
  15. // switching.
  16. //
  17. // Author:
  18. //
  19. // David N. Cutler (davec) 1-Apr-1991
  20. // Joe Notarangelo 05-Jun-1992
  21. //
  22. // Environment:
  23. //
  24. // Kernel mode only, IRQL DISPATCH_LEVEL.
  25. //
  26. // Revision History:
  27. //
  28. //--
  29. #include "ksalpha.h"
  30. // #define _COLLECT_SWITCH_DATA_ 1
  31. SBTTL("Unlock Dispatcher Database")
  32. //++
  33. //
  34. // VOID
  35. // KiUnlockDispatcherDatabase (
  36. // IN KIRQL OldIrql
  37. // )
  38. //
  39. // Routine Description:
  40. //
  41. // This routine is entered at IRQL DISPATCH_LEVEL with the dispatcher
  42. // database locked. Ifs function is to either unlock the dispatcher
  43. // database and return or initiate a context switch if another thread
  44. // has been selected for execution.
  45. //
  46. // N.B. A context switch CANNOT be initiated if the previous IRQL
  47. // is DISPATCH_LEVEL.
  48. //
  49. // N.B. This routine is carefully written to be a leaf function. If,
  50. // however, a context swap should be performed, the routine is
  51. // switched to a nested function.
  52. //
  53. // Arguments:
  54. //
  55. // OldIrql (a0) - Supplies the IRQL when the dispatcher database
  56. // lock was acquired.
  57. //
  58. // Return Value:
  59. //
  60. // None.
  61. //
  62. //--
  63. LEAF_ENTRY(KiUnlockDispatcherDatabase)
  64. //
  65. // Check if a thread has been scheduled to execute on the current processor
  66. //
  67. GET_PROCESSOR_CONTROL_BLOCK_BASE // get prcb address
  68. cmpult a0, DISPATCH_LEVEL, t1 // check if IRQL below dispatch level
  69. LDP t2, PbNextThread(v0) // get next thread address
  70. bne t2, 30f // if ne, next thread selected
  71. //
  72. // Release dispatcher database lock, restore IRQL to its previous level
  73. // and return
  74. //
  75. 10: //
  76. #if !defined(NT_UP)
  77. bis a0, zero, a1 // set old IRQL value
  78. ldil a0, LockQueueDispatcherLock // set lock queue number
  79. br zero, KeReleaseQueuedSpinLock // release dispatcher lock
  80. #else
  81. SWAP_IRQL // lower IRQL
  82. ret zero, (ra) // return
  83. #endif
  84. //
  85. // A new thread has been selected to run on the current processor, but
  86. // the new IRQL is not below dispatch level. If the current processor is
  87. // not executing a DPC, then request a dispatch interrupt on the current
  88. // processor before releasing the dispatcher lock and restoring IRQL.
  89. //
  90. 20: ldl t2, PbDpcRoutineActive(v0) // check if DPC routine active
  91. bne t2,10b // if ne, DPC routine active
  92. #if !defined(NT_UP)
  93. bis a0, zero, t0 // save old IRQL value
  94. ldil a0, DISPATCH_LEVEL // set interrupt request level
  95. REQUEST_SOFTWARE_INTERRUPT // request DPC interrupt
  96. ldil a0, LockQueueDispatcherLock // set lock queue number
  97. bis t0, zero, a1 // set old IRQL value
  98. br zero, KeReleaseQueuedSpinLock // release dispatcher lock
  99. #else
  100. SWAP_IRQL // lower IRQL
  101. ldil a0, DISPATCH_LEVEL // set interrupt request level
  102. REQUEST_SOFTWARE_INTERRUPT // request DPC interrupt
  103. ret zero, (ra) // return
  104. #endif
  105. //
  106. // A new thread has been selected to run on the current processor.
  107. //
  108. // If the new IRQL is less than dispatch level, then switch to the new
  109. // thread.
  110. //
  111. 30: beq t1, 20b // if eq, not below dispatch level
  112. .end KiUnlockDispatcherDatabase
  113. //
  114. // N.B. This routine is carefully written as a nested function.
  115. // Control only reaches this routine from above.
  116. //
  117. // v0 contains the address of PRCB
  118. // t2 contains the next thread
  119. //
  120. NESTED_ENTRY(KxUnlockDispatcherDatabase, ExceptionFrameLength, zero)
  121. lda sp, -ExceptionFrameLength(sp) // allocate context frame
  122. stq ra, ExIntRa(sp) // save return address
  123. stq s0, ExIntS0(sp) // save integer registers
  124. stq s1, ExIntS1(sp) //
  125. stq s2, ExIntS2(sp) //
  126. stq s3, ExIntS3(sp) //
  127. stq s4, ExIntS4(sp) //
  128. stq s5, ExIntS5(sp) //
  129. stq fp, ExIntFp(sp) //
  130. PROLOGUE_END
  131. bis v0, zero, s0 // set address of PRCB
  132. GET_CURRENT_THREAD // get current thread address
  133. bis v0, zero, s1 // set current thread address
  134. bis t2, zero, s2 // set next thread address
  135. StoreByte(a0, ThWaitIrql(s1)) // save previous IRQL
  136. STP zero, PbNextThread(s0) // clear next thread address
  137. //
  138. // Reready current thread for execution and swap context to the selected thread.
  139. //
  140. // N.B. The return from the call to swap context is directly to the swap
  141. // thread exit.
  142. //
  143. bis s1, zero, a0 // set previous thread address
  144. STP s2, PbCurrentThread(s0) // set address of current thread object
  145. bsr ra, KiReadyThread // reready thread for execution
  146. lda ra, KiSwapThreadExit // set return address
  147. jmp SwapContext // swap context
  148. .end KxUnlockDispatcherDatabase
  149. SBTTL("Swap Thread")
  150. //++
  151. //
  152. // INT_PTR
  153. // KiSwapThread (
  154. // VOID
  155. // )
  156. //
  157. // Routine Description:
  158. //
  159. // This routine is called to select the next thread to run on the
  160. // current processor and to perform a context switch to the thread.
  161. //
  162. // Arguments:
  163. //
  164. // None.
  165. //
  166. // Return Value:
  167. //
  168. // Wait completion status (v0).
  169. //
  170. //--
  171. NESTED_ENTRY(KiSwapThread, ExceptionFrameLength, zero)
  172. lda sp, -ExceptionFrameLength(sp) // allocate context frame
  173. stq ra, ExIntRa(sp) // save return address
  174. stq s0, ExIntS0(sp) // save integer registers s0 - s5
  175. stq s1, ExIntS1(sp) //
  176. stq s2, ExIntS2(sp) //
  177. stq s3, ExIntS3(sp) //
  178. stq s4, ExIntS4(sp) //
  179. stq s5, ExIntS5(sp) //
  180. stq fp, ExIntFp(sp) // save fp
  181. PROLOGUE_END
  182. GET_PROCESSOR_CONTROL_REGION_BASE // get pcr address
  183. bis v0, zero, s3 // save PCR address
  184. LDP s0, PcPrcb(s3) // get address of PRCB
  185. ldl s5, KiReadySummary // get ready summary
  186. zapnot s5, 0x0f, t0 // clear high 32 bits
  187. GET_CURRENT_THREAD // get current thread address
  188. bis v0, zero, s1 // set current thread address
  189. LDP s2, PbNextThread(s0) // get next thread address
  190. #if !defined(NT_UP)
  191. ldl fp, PcSetMember(s3) // get processor affinity mask
  192. #endif
  193. STP zero, PbNextThread(s0) // zero next thread address
  194. bne s2, 120f // if ne, next thread selected
  195. //
  196. // Find the highest nibble in the ready summary that contains a set bit
  197. // and left justify so the nibble is in bits <63:60>.
  198. //
  199. cmpbge zero, t0, s4 // generate mask of clear bytes
  200. ldil t2, 7 // set initial bit number
  201. srl s4, 1, t5 // check bits <15:8>
  202. cmovlbc t5, 15, t2 // if bit clear, bit number = 15
  203. srl s4, 2, t6 // check bits <23:16>
  204. cmovlbc t6, 23, t2 // if bit clear, bit number = 23
  205. srl s4, 3, t7 // check bits <31:24>
  206. cmovlbc t7, 31, t2 // if bit clear, bit number = 31
  207. bic t2, 7, t3 // get byte shift from priority
  208. srl t0, t3, s4 // isolate highest nonzero byte
  209. and s4, 0xf0, t4 // check if high nibble nonzero
  210. subq t2, 4, t1 // compute bit number if high nibble zero
  211. cmoveq t4, t1, t2 // if eq, high nibble zero
  212. 10: ornot zero, t2, t4 // compute left justify shift count
  213. sll t0, t4, t0 // left justify ready summary to nibble
  214. //
  215. // If the next bit is set in the ready summary, then scan the corresponding
  216. // dispatcher ready queue.
  217. //
  218. 30: blt t0, 50f // if ltz, queue contains an entry
  219. 31: sll t0, 1, t0 // position next ready summary bit
  220. subq t2, 1, t2 // decrement ready queue priority
  221. bne t0, 30b // if ne, more queues to scan
  222. //
  223. // All ready queues were scanned without finding a runnable thread so
  224. // default to the idle thread and set the appropirate bit in idle summary.
  225. //
  226. #if defined(_COLLECT_SWITCH_DATA_)
  227. lda t0, KeThreadSwitchCounters // get switch counters address
  228. ldl v0, TwSwitchToIdle(t0) // increment switch to idle count
  229. addl v0, 1, v0 //
  230. stl v0, TwSwitchToIdle(t0) //
  231. #endif
  232. #if defined(NT_UP)
  233. ldil t0, 1 // get current idle summary
  234. #else
  235. ldl t0, KiIdleSummary // get current idle summary
  236. bis t0, fp, t0 // set member bit in idle summary
  237. #endif
  238. stl t0, KiIdleSummary // set new idle summary
  239. LDP s2, PbIdleThread(s0) // set address of idle thread
  240. br zero, 120f // swap context
  241. //
  242. // Compute address of ready list head and scan reday queue for a runnable
  243. // thread.
  244. //
  245. 50: lda t1, KiDispatcherReadyListHead // get ready ready base address
  246. #if defined(_AXP64_)
  247. sll t2, 4, s4 // compute ready queue address
  248. addq s4, t1, s4 //
  249. #else
  250. s8addl t2, t1, s4 // compute ready queue address
  251. #endif
  252. LDP t4, LsFlink(s4) // get address of next queue entry
  253. 55: SUBP t4, ThWaitListEntry, s2 // compute address of thread object
  254. //
  255. // If the thread can execute on the current processor, then remove it from
  256. // the dispatcher ready queue.
  257. //
  258. #if !defined(NT_UP)
  259. ldl t5, ThAffinity(s2) // get thread affinity
  260. and t5, fp, t6 // the current processor
  261. bne t6, 60f // if ne, thread affinity compatible
  262. LDP t4, LsFlink(t4) // get address of next entry
  263. cmpeq t4, s4, t1 // check for end of list
  264. beq t1, 55b // if eq, not end of list
  265. br zero, 31b //
  266. //
  267. // If the thread last ran on the current processor, the processor is the
  268. // ideal processor for the thread, the thread has been waiting for longer
  269. // than a quantum, ot its priority is greater than low realtime plus 9,
  270. // then select the thread. Otherwise, an attempt is made to find a more
  271. // appropriate candidate.
  272. //
  273. 60: ldq_u t1, PcNumber(s3) // get current processor number
  274. extbl t1, PcNumber % 8, t12 //
  275. ldq_u t11, ThNextProcessor(s2) // get last processor number
  276. extbl t11, ThNextProcessor % 8, t9 //
  277. cmpeq t9, t12, t5 // check thread's last processor
  278. bne t5, 110f // if eq, last processor match
  279. ldq_u t6, ThIdealProcessor(s2) // get thread's ideal processor number
  280. extbl t6, ThIdealProcessor % 8, a3 //
  281. cmpeq a3, t12, t8 // check thread's ideal processor
  282. bne t8, 100f // if eq, ideal processor match
  283. ldl t6, KeTickCount // get low part of tick count
  284. ldl t7, ThWaitTime(s2) // get time of thread ready
  285. subq t6, t7, t8 // compute length of wait
  286. cmpult t8, READY_SKIP_QUANTUM + 1, t1 // check if wait time exceeded
  287. cmpult t2, LOW_REALTIME_PRIORITY + 9, t3 // check if priority in range
  288. and t1, t3, v0 // check if priority and time match
  289. beq v0, 100f // if eq, select this thread
  290. //
  291. // Search forward in the ready queue until the end of the list is reached
  292. // or a more appropriate thread is found.
  293. //
  294. LDP t7, LsFlink(t4) // get address of next entry
  295. 80: cmpeq t7, s4, t1 // if eq, end of list
  296. bne t1, 100f // select original thread
  297. SUBP t7, ThWaitListEntry, a0 // compute address of thread object
  298. ldl a2, ThAffinity(a0) // get thread affinity
  299. and a2, fp, t1 // check for compatibile thread affinity
  300. beq t1, 85f // if eq, thread affinity not compatible
  301. ldq_u t5, ThNextProcessor(a0) // get last processor number
  302. extbl t5, ThNextProcessor % 8, t9 //
  303. cmpeq t9, t12, t10 // check if last processor number match
  304. bne t10, 90f // if ne, last processor match
  305. ldq_u a1, ThIdealProcessor(a0) // get ideal processor number
  306. extbl a1, ThIdealProcessor % 8, a3 //
  307. cmpeq a3, t12, t10 // check if ideal processor match
  308. bne t10, 90f // if ne, ideal processor match
  309. 85: ldl t8, ThWaitTime(a0) // get time of thread ready
  310. LDP t7, LsFlink(t7) // get address of next entry
  311. subq t6, t8, t8 // compute length of wait
  312. cmpult t8, READY_SKIP_QUANTUM + 1, t5 // check if wait time exceeded
  313. bne t5, 80b // if ne, wait time not exceeded
  314. br zero, 100f // select original thread
  315. //
  316. // Last processor or ideal processor match.
  317. //
  318. 90: bis a0, zero, s2 // set thread address
  319. bis t7, zero, t4 // set list entry address
  320. bis t5, zero, t11 // copy last processor data
  321. 100: insbl t12, ThNextProcessor % 8, t8 // move next processor into position
  322. mskbl t11, ThNextProcessor % 8, t5 // mask next processor position
  323. bis t8, t5, t6 // merge
  324. stq_u t6, ThNextProcessor(s2) // update next processor
  325. 110: //
  326. #if defined(_COLLECT_SWITCH_DATA_)
  327. ldq_u t5, ThNextProcessor(s2) // get last processor number
  328. extbl t5, ThNextProcessor % 8, t9 //
  329. ldq_u a1, ThIdealProcessor(s2) // get ideal processor number
  330. extbl a1, ThIdealProcessor % 8, a3 //
  331. lda t0, KeThreadSwitchCounters + TwFindAny // compute address of Any counter
  332. ADDP t0, TwFindIdeal-TwFindAny, t1 // compute address of Ideal counter
  333. cmpeq t9, t12, t7 // if eq, last processor match
  334. ADDP t0, TwFindLast-TwFindAny, t6 // compute address of Last counter
  335. cmpeq a3, t12, t5 // check if ideal processor match
  336. cmovne t7, t6, t0 // if last match, use last counter
  337. cmovne t5, t1, t0 // if ideal match, use ideal counter
  338. ldl v0, 0(t0) // increment counter
  339. addl v0, 1, v0 //
  340. stl v0, 0(t0) //
  341. #endif
  342. #endif
  343. LDP t5, LsFlink(t4) // get list entry forward link
  344. LDP t6, LsBlink(t4) // get list entry backward link
  345. STP t5, LsFlink(t6) // set forward link in previous entry
  346. STP t6, LsBlink(t5) // set backward link in next entry
  347. cmpeq t6, t5, t7 // if eq, list is empty
  348. beq t7, 120f //
  349. ldil t1, 1 // compute ready summary set member
  350. sll t1, t2, t1 //
  351. xor t1, s5, t1 // clear member bit in ready summary
  352. stl t1, KiReadySummary //
  353. //
  354. // Swap context to the next thread
  355. //
  356. 120: STP s2, PbCurrentThread(s0) // set address of current thread object
  357. bsr ra, SwapContext // swap context
  358. //
  359. // Lower IRQL, deallocate context frame, and return wait completion status.
  360. //
  361. // N.B. SwapContext releases the dispatcher database lock.
  362. //
  363. // N.B. The register v0 contains the complement of the kernel APC pending state.
  364. //
  365. // N.B. The register s2 contains the address of the new thread.
  366. //
  367. ALTERNATE_ENTRY(KiSwapThreadExit)
  368. LDP s1, ThWaitStatus(s2) // get wait completion status
  369. ldq_u t1, ThWaitIrql(s2) // get original IRQL
  370. extbl t1, ThWaitIrql % 8, a0 //
  371. bis v0, a0, t3 // check if APC pending and IRQL is zero
  372. bne t3, 10f // if ne, APC not pending or IRQL not zero
  373. //
  374. // Lower IRQL to APC level and dispatch APC interrupt.
  375. //
  376. ldil a0, APC_LEVEL // lower IRQL to APC level
  377. SWAP_IRQL //
  378. ldil a0, APC_LEVEL // clear software interrupt
  379. DEASSERT_SOFTWARE_INTERRUPT //
  380. GET_PROCESSOR_CONTROL_BLOCK_BASE // get current prcb address
  381. ldl t1, PbApcBypassCount(v0) // increment the APC bypass count
  382. addl t1, 1, t2 //
  383. stl t2, PbApcBypassCount(v0) //
  384. bis zero, zero, a0 // set previous mode to kernel
  385. bis zero, zero, a1 // set exception frame address
  386. bis zero, zero, a2 // set trap frame address
  387. bsr ra, KiDeliverApc // deliver kernel mode APC
  388. bis zero, zero, a0 // set original wait IRQL
  389. //
  390. // Lower IRQL to wait level, set return status, restore registers, and
  391. // return.
  392. //
  393. 10: SWAP_IRQL // lower IRQL to wait level
  394. bis s1, zero, v0 // set return status value
  395. ldq ra, ExIntRa(sp) // restore return address
  396. ldq s0, ExIntS0(sp) // restore int regs S0-S5
  397. ldq s1, ExIntS1(sp) //
  398. ldq s2, ExIntS2(sp) //
  399. ldq s3, ExIntS3(sp) //
  400. ldq s4, ExIntS4(sp) //
  401. ldq s5, ExIntS5(sp) //
  402. ldq fp, ExIntFp(sp) // restore fp
  403. lda sp, ExceptionFrameLength(sp) // deallocate context frame
  404. ret zero, (ra) // return
  405. .end KiSwapThread
  406. SBTTL("Dispatch Interrupt")
  407. //++
  408. //
  409. // Routine Description:
  410. //
  411. // This routine is entered as the result of a software interrupt generated
  412. // at DISPATCH_LEVEL. Its function is to process the Deferred Procedure Call
  413. // (DPC) list, and then perform a context switch if a new thread has been
  414. // selected for execution on the processor.
  415. //
  416. // This routine is entered at IRQL DISPATCH_LEVEL with the dispatcher
  417. // database unlocked. When a return to the caller finally occurs, the
  418. // IRQL remains at DISPATCH_LEVEL, and the dispatcher database is still
  419. // unlocked.
  420. //
  421. // N.B. On entry to this routine only the volatile integer registers have
  422. // been saved. The volatile floating point registers have not been saved.
  423. //
  424. // Arguments:
  425. //
  426. // fp - Supplies a pointer to the base of a trap frame.
  427. //
  428. // Return Value:
  429. //
  430. // None.
  431. //
  432. //--
  433. .struct 0
  434. DpSp: .space 8 // saved stack pointer
  435. DpBs: .space 8 // base of previous stack
  436. DpLim: .space 8 // limit of previous stack
  437. .space 8 // pad to octaword
  438. DpcFrameLength: // DPC frame length
  439. NESTED_ENTRY(KiDispatchInterrupt, ExceptionFrameLength, zero)
  440. lda sp, -ExceptionFrameLength(sp) // allocate exception frame
  441. stq ra, ExIntRa(sp) // save return address
  442. //
  443. // Save the saved registers in case we context switch to a new thread.
  444. //
  445. // N.B. - If we don't context switch then we need only restore those
  446. // registers that we use in this routine, currently those registers
  447. // are s0, s1
  448. //
  449. stq s0, ExIntS0(sp) // save integer registers s0-s6
  450. stq s1, ExIntS1(sp) //
  451. stq s2, ExIntS2(sp) //
  452. stq s3, ExIntS3(sp) //
  453. stq s4, ExIntS4(sp) //
  454. stq s5, ExIntS5(sp) //
  455. stq fp, ExIntFp(sp) //
  456. PROLOGUE_END
  457. //
  458. // Increment the dispatch interrupt count
  459. //
  460. GET_PROCESSOR_CONTROL_BLOCK_BASE // get current prcb address
  461. bis v0, zero, s0 // save current prcb address
  462. ldl t2, PbDispatchInterruptCount(s0) // increment dispatch interrupt count
  463. addl t2, 1, t3 //
  464. stl t3, PbDispatchInterruptCount(s0) //
  465. //
  466. // Process the DPC List with interrupts off.
  467. //
  468. ldl t0, PbDpcQueueDepth(s0) // get current queue depth
  469. beq t0, 20f // if eq, no DPCs pending
  470. //
  471. // Save current initial kernel stack address and set new initial kernel stack
  472. // address.
  473. //
  474. PollDpcList: //
  475. DISABLE_INTERRUPTS // disable interrupts
  476. GET_PROCESSOR_CONTROL_REGION_BASE // get current PCR address
  477. LDP a0, PcDpcStack(v0) // get address of DPC stack
  478. lda t0, -DpcFrameLength(a0) // allocate DPC frame
  479. LDP t4, PbCurrentThread(s0) // get current thread
  480. LDP t5, ThStackLimit(t4) // get current stack limit
  481. stq sp, DpSp(t0) // save old stack pointer
  482. stq t5, DpLim(t0) // save old stack limit
  483. SUBP a0, KERNEL_STACK_SIZE, t5 // compute new stack limit
  484. STP t5, ThStackLimit(t4) // store new stack limit
  485. bis t0, t0, sp // set new stack pointer
  486. SET_INITIAL_KERNEL_STACK // set new initial kernel stack
  487. stq v0, DpBs(sp) // save previous initial stack
  488. bsr ra, KiRetireDpcList // process the DPC list
  489. //
  490. // Switch back to previous stack and restore the initial stack limit.
  491. //
  492. ldq a0, DpBs(sp) // get previous initial stack address
  493. ldq t5, DpLim(sp) // get old stack limit
  494. SET_INITIAL_KERNEL_STACK // reset current initial stack
  495. ldq sp, DpSp(sp) // restore stack pointer
  496. LDP t4, PbCurrentThread(s0) // get current thread
  497. STP t5, ThStackLimit(t4) // restore stack limit
  498. ENABLE_INTERRUPTS // enable interrupts
  499. //
  500. // Check to determine if quantum end has occured.
  501. //
  502. 20: ldl t0, PbQuantumEnd(s0) // get quantum end indicator
  503. beq t0, 25f // if eq, no quantum end request
  504. stl zero, PbQuantumEnd(s0) // clear quantum end indicator
  505. bsr ra, KiQuantumEnd // process quantum end request
  506. beq v0, 50f // if eq, no next thread, return
  507. bis v0, zero, s2 // set next thread
  508. br zero, 40f // else restore interrupts and return
  509. //
  510. // Determine if a new thread has been selected for execution on
  511. // this processor.
  512. //
  513. 25: LDP v0, PbNextThread(s0) // get address of next thread object
  514. beq v0, 50f // if eq, no new thread selected
  515. //
  516. // Lock dispatcher database and reread address of next thread object
  517. // since it is possible for it to change in mp sysytem.
  518. //
  519. // N.B. This is a very special acquire of the dispatcher lock in that it
  520. // will not be acquired unless it is free. Therefore, it is known
  521. // that there cannot be any queued lock requests.
  522. //
  523. #if !defined(NT_UP)
  524. lda s1, KiDispatcherLock // get dispatcher base lock address
  525. ldil s2, LockQueueDispatcherLock * 2 // compute per processor
  526. SPADDP s2, s0, s2 // lock queue entry address
  527. lda s2, PbLockQueue(s2) //
  528. #endif
  529. 30: ldl a0, KiSynchIrql // raise IRQL to synch level
  530. SWAP_IRQL //
  531. #if !defined(NT_UP)
  532. LDP_L t0, 0(s1) // get current lock value
  533. bis s2, zero, t1 // t1 = lock ownership value
  534. bne t0, 45f // ne => spin lock owned
  535. STP_C t1, 0(s1) // set lock to owned
  536. beq t1, 45f // if eq, conditional store failed
  537. mb // synchronize memory access
  538. bis s1, LOCK_QUEUE_OWNER, t0 // set lock owner bit in lock entry
  539. STP t0, LqLock(s2) //
  540. #endif
  541. //
  542. // Reready current thread for execution and swap context to the selected thread.
  543. //
  544. LDP s2, PbNextThread(s0) // get addr of next thread
  545. 40: GET_CURRENT_THREAD // get current thread address
  546. bis v0, zero, s1 // save current thread address
  547. STP zero, PbNextThread(s0) // clear address of next thread
  548. STP s2, PbCurrentThread(s0) // set address of current thread
  549. bis s1, zero, a0 // set address of previous thread
  550. bsr ra, KiReadyThread // reready thread for execution
  551. bsr ra, KiSaveVolatileFloatState // save floating state
  552. bsr ra, SwapContext // swap context
  553. //
  554. // Restore the saved integer registers that were changed for a context
  555. // switch only.
  556. //
  557. // N.B. - The frame pointer must be restored before the volatile floating
  558. // state because it is the pointer to the trap frame.
  559. //
  560. ldq s2, ExIntS2(sp) // restore s2 - s5
  561. ldq s3, ExIntS3(sp) //
  562. ldq s4, ExIntS4(sp) //
  563. ldq s5, ExIntS5(sp) //
  564. ldq fp, ExIntFp(sp) // restore the frame pointer
  565. bsr ra, KiRestoreVolatileFloatState // restore floating state
  566. //
  567. // Restore the remaining saved integer registers and return.
  568. //
  569. 50: ldq s0, ExIntS0(sp) // restore s0 - s1
  570. ldq s1, ExIntS1(sp) //
  571. ldq ra, ExIntRa(sp) // get return address
  572. lda sp, ExceptionFrameLength(sp) // deallocate context frame
  573. ret zero, (ra) // return
  574. //
  575. // Dispatcher lock is owned, spin on both the the dispatcher lock and
  576. // the DPC queue going not empty.
  577. //
  578. #if !defined(NT_UP)
  579. 45: bis v0, zero, a0 // lower IRQL to wait for locks
  580. SWAP_IRQL //
  581. 48: LDP t0, 0(s1) // read current dispatcher lock value
  582. beq t0, 30b // lock available. retry spinlock
  583. ldl t1, PbDpcQueueDepth(s0) // get current DPC queue depth
  584. bne t1, PollDpcList // if ne, list not empty
  585. br zero, 48b // loop in cache until lock available
  586. #endif
  587. .end KiDispatchInterrupt
  588. SBTTL("Swap Context to Next Thread")
  589. //++
  590. //
  591. // Routine Description:
  592. //
  593. // This routine is called to swap context from one thread to the next.
  594. //
  595. // Arguments:
  596. //
  597. // s0 - Address of Processor Control Block (PRCB).
  598. // s1 - Address of previous thread object.
  599. // s2 - Address of next thread object.
  600. // sp - Pointer to a exception frame.
  601. //
  602. // Return value:
  603. //
  604. // v0 - complement of Kernel APC pending.
  605. // s2 - Address of current thread object.
  606. //
  607. //--
  608. NESTED_ENTRY(SwapContext, 0, zero)
  609. stq ra, ExSwapReturn(sp) // save return address
  610. PROLOGUE_END
  611. //
  612. // Set new thread's state to running. Note this must be done
  613. // under the dispatcher lock so that KiSetPriorityThread sees
  614. // the correct state.
  615. //
  616. ldil t0, Running // set state of new thread to running
  617. StoreByte( t0, ThState(s2) ) //
  618. //
  619. // Acquire the context swap lock so the address space of the old thread
  620. // cannot be deleted and then release the dispatcher database lock.
  621. //
  622. // N.B. This lock is used to protect the address space until the context
  623. // switch has sufficiently progressed to the point where the address
  624. // space is no longer needed. This lock is also acquired by the reaper
  625. // thread before it finishes thread termination.
  626. //
  627. #if !defined(NT_UP)
  628. ldil a0, LockQueueContextSwapLock * 2 // compute per processor
  629. SPADDP a0, s0, a0 // lock queue entry address
  630. lda a0, PbLockQueue(a0) //
  631. bsr ra, KeAcquireQueuedSpinLockAtDpcLevel // acquire context swap lock
  632. ldil a0, LockQueueDispatcherLock * 2 // compute per processor
  633. SPADDP a0, s0, a0 // lock queue entry address
  634. lda a0, PbLockQueue(a0) //
  635. bsr ra, KeReleaseQueuedSpinLockFromDpcLevel // release dispatcher lock
  636. #endif
  637. //
  638. // Accumulate the total time spent in a thread.
  639. //
  640. #if defined(PERF_DATA)
  641. bis zero,zero,a0 // optional frequency not required
  642. bsr ra, KeQueryPerformanceCounter // 64-bit cycle count in v0
  643. ldq t0, PbStartCount(s0) // get starting cycle count
  644. stq v0, PbStartCount(s0) // set starting cycle count
  645. ldl t1, EtPerformanceCountHigh(s1) // get accumulated cycle count high
  646. sll t1, 32, t2 //
  647. ldl t3, EtPerformanceCountLow(s1) // get accumulated cycle count low
  648. zap t3, 0xf0, t4 // zero out high dword sign extension
  649. bis t2, t4, t3 //
  650. subq v0, t0, t5 // compute elapsed cycle count
  651. addq t5, t3, t4 // compute new cycle count
  652. stl t4, EtPerformanceCountLow(s1) // set new cycle count in thread
  653. srl t4, 32, t2 //
  654. stl t2, EtPerformanceCountHigh(s1) //
  655. #endif
  656. bsr ra, KiSaveNonVolatileFloatState // save floating state
  657. //
  658. // The following entry point is used to switch from the idle thread to
  659. // another thread.
  660. //
  661. ALTERNATE_ENTRY(SwapFromIdle)
  662. //
  663. // Check if an attempt is being made to swap context while executing a DPC.
  664. //
  665. ldl v0, PbDpcRoutineActive(s0) // get DPC routine active flag
  666. beq v0, 10f //
  667. ldil a0, ATTEMPTED_SWITCH_FROM_DPC // set bug check code
  668. bsr ra, KeBugCheck // call bug check routine
  669. //
  670. // Get address of old and new process objects.
  671. //
  672. 10: LDP s5, ThApcState + AsProcess(s1) // get address of old process
  673. LDP s4, ThApcState + AsProcess(s2) // get address of new process
  674. //
  675. // Save the current PSR in the context frame, store the kernel stack pointer
  676. // in the previous thread object, load the new kernel stack pointer from the
  677. // new thread object, load the ptes for the new kernel stack in the DTB
  678. // stack, select and new process id and swap to the new process, and restore
  679. // the previous PSR from the context frame.
  680. //
  681. DISABLE_INTERRUPTS // disable interrupts
  682. LDP a0, ThInitialStack(s2) // get initial kernel stack pointer
  683. STP sp, ThKernelStack(s1) // save old kernel stack pointer
  684. bis s2, zero, a1 // new thread address
  685. LDP a2, ThTeb(s2) // get address of user TEB
  686. //
  687. // On uni-processor systems keep the global current thread address
  688. // up to date.
  689. //
  690. #ifdef NT_UP
  691. STP a1, KiCurrentThread // save new current thread
  692. #endif //NT_UP
  693. //
  694. // If the old process is the same as the new process, then there is no need
  695. // to change the address space. The a3 parameter indicates that the address
  696. // space is not to be swapped if it is less than zero. Otherwise, a3 will
  697. // contain the pfn of the PDR for the new address space.
  698. //
  699. ldil a3, -1 // assume no address space change
  700. cmpeq s5, s4, t0 // old process = new process?
  701. bne t0, 50f // if ne, no address space swap
  702. //
  703. // Update the processor set masks. Clear the processor set member number in
  704. // the old process and set the processor member number in the new process.
  705. //
  706. #if !defined(NT_UP)
  707. ldl t0, PbSetMember(s0) // get processor set member mask
  708. ldq t1, PrActiveProcessors(s5) // get old processor sets
  709. ldq t2, PrActiveProcessors(s4) // get new processor sets
  710. bic t1, t0, t3 // clear member in old active set
  711. bis t2, t0, t4 // set member in new active set
  712. sll t0, 32, t5 // set member in new run on set
  713. bis t4, t5, t4 //
  714. stq t3, PrActiveProcessors(s5) // set old processor sets
  715. stq t4, PrActiveProcessors(s4) // set new processor sets
  716. #endif
  717. LDP a3, PrDirectoryTableBase(s4) // get page directory PDE
  718. srl a3, PTE_PFN, a3 // isolate page frame number
  719. //
  720. // If the maximum address space number is zero, then force a TB invalidate.
  721. //
  722. ldl a4, KiMaximumAsn // get maximum ASN number
  723. bis zero, 1, a5 // set ASN wrap indicator
  724. beq a4, 50f // if eq, only one ASN
  725. bis a4, zero, t3 // save maximum ASN number
  726. //
  727. // Check if a pending TB invalidate is pending on the current processor.
  728. //
  729. #if !defined(NT_UP)
  730. lda t8, KiTbiaFlushRequest // get TBIA flush request mask address
  731. ldl t1, 0(t8) // get TBIA flush request mask
  732. and t1, t0, t2 // check if current processor request
  733. beq t2, 20f // if eq, no pending flush request
  734. bic t1, t0, t1 // clear processor member in mask
  735. stl t1, 0(t8) // set TBIA flush request mask
  736. #endif
  737. //
  738. // If the process sequence number matches the master sequence number then
  739. // use the process ASN. Otherwise, allocate a new ASN and check for wrap.
  740. // If ASN wrap occurs, then also increment the master sequence number.
  741. //
  742. 20: lda t9, KiMasterSequence // get master sequence number address
  743. ldq t4, 0(t9) // get master sequence number
  744. ldq t5, PrProcessSequence(s4) // get process sequence number
  745. ldl a4, PrProcessAsn(s4) // get process ASN
  746. xor t4, t5, a5 // check if sequence number matches
  747. beq a5, 40f // if eq, sequence number match
  748. lda t10, KiMasterAsn // get master ASN number address
  749. ldl a4, 0(t10) // get master ASN number
  750. addl a4, 1, a4 // increment master ASN number
  751. cmpult t3, a4, a5 // check for ASN wrap
  752. beq a5, 30f // if eq, ASN did not wrap
  753. addq t4, 1, t4 // increment master sequence number
  754. stq t4, 0(t9) // set master sequence number
  755. #if !defined(NT_UP)
  756. ldl t5, KeActiveProcessors // get active processor mask
  757. bic t5, t0, t5 // clear current processor member
  758. stl t5, 0(t8) // request flush on other processors
  759. #endif
  760. bis zero, zero, a4 // reset master ASN
  761. 30: stl a4, 0(t10) // set master ASN number
  762. stl a4, PrProcessAsn(s4) // set process ASN number
  763. stq t4, PrProcessSequence(s4) // set process sequence number
  764. #if !defined(NT_UP)
  765. ldq t5, PrActiveProcessors(s4) // get new processor sets
  766. zapnot t5, 0xf, t5 // clear run on processor set
  767. sll t5, 32, t3 // set run on set equal to active set
  768. bis t5, t3, t5 //
  769. stq t5, PrActiveProcessors(s4) // set new processor sets
  770. #endif
  771. //
  772. // Merge TBIA flush request with ASN wrap indicator.
  773. //
  774. 40: //
  775. #if !defined(NT_UP)
  776. bis t2, a5, a5 // merge TBIA indicators
  777. #endif
  778. //
  779. // a0 = initial ksp of new thread
  780. // a1 = new thread address
  781. // a2 = new TEB
  782. // a3 = PDR of new address space or -1
  783. // a4 = new ASN
  784. // a5 = ASN wrap indicator
  785. //
  786. 50: SWAP_THREAD_CONTEXT // swap thread
  787. LDP sp, ThKernelStack(s2) // get new kernel stack pointer
  788. ENABLE_INTERRUPTS // enable interrupts
  789. //
  790. // Release the context swap lock.
  791. //
  792. #if !defined(NT_UP)
  793. ldil a0, LockQueueContextSwapLock * 2 // compute per processor
  794. SPADDP a0, s0, a0 // lock queue entry address
  795. lda a0, PbLockQueue(a0) //
  796. bsr ra, KeReleaseQueuedSpinLockFromDpcLevel // release context swap lock
  797. #endif
  798. //
  799. // If the new thread has a kernel mode APC pending, then request an APC
  800. // interrupt.
  801. //
  802. ldil v0, 1 // set no apc pending
  803. LoadByte(t0, ThApcState + AsKernelApcPending(s2)) // get kernel APC pendng
  804. ldl t2, ExPsr(sp) // get previous processor status
  805. beq t0, 50f // if eq no apc pending
  806. ldil a0, APC_INTERRUPT // set APC level value
  807. REQUEST_SOFTWARE_INTERRUPT // request an apc interrupt
  808. bis zero, zero, v0 // set APC pending
  809. //
  810. // Count number of context switches.
  811. //
  812. 50: ldl t1, PbContextSwitches(s0) // increment number of switches
  813. addl t1, 1, t1 //
  814. stl t1, PbContextSwitches(s0) //
  815. ldl t0, ThContextSwitches(s2) // increment thread switches
  816. addl t0, 1, t0 //
  817. stl t0, ThContextSwitches(s2) //
  818. //
  819. // Restore the nonvolatile floating state.
  820. //
  821. bsr ra, KiRestoreNonVolatileFloatState //
  822. //
  823. // load RA and return with address of current thread in s2
  824. //
  825. ldq ra, ExSwapReturn(sp) // get return address
  826. ret zero, (ra) // return
  827. .end SwapContext
  828. SBTTL("Swap Process")
  829. //++
  830. //
  831. // BOOLEAN
  832. // KiSwapProcess (
  833. // IN PKPROCESS NewProcess
  834. // IN PKPROCESS OldProcess
  835. // )
  836. //
  837. // Routine Description:
  838. //
  839. // This function swaps the address space from one process to another by
  840. // assigning a new ASN if necessary and calling the palcode to swap
  841. // the privileged portion of the process context (the page directory
  842. // base pointer and the ASN). This function also maintains the processor
  843. // set for both processes in the switch.
  844. //
  845. // Arguments:
  846. //
  847. // NewProcess (a0) - Supplies a pointer to a control object of type process
  848. // which represents the new process to switch to.
  849. //
  850. // OldProcess (a1) - Supplies a pointer to a control object of type process
  851. // which represents the old process to switch from..
  852. //
  853. // Return Value:
  854. //
  855. // None.
  856. //
  857. //--
  858. .struct 0
  859. SwA0: .space 8 // saved new process address
  860. SwA1: .space 8 // saved old process address
  861. SwRa: .space 8 // saved return address
  862. .space 8 // unused
  863. SwapFrameLength: // swap frame length
  864. NESTED_ENTRY(KiSwapProcess, SwapFrameLength, zero)
  865. lda sp, -SwapFrameLength(sp) // allocate stack frame
  866. stq ra, SwRa(sp) // save return address
  867. PROLOGUE_END
  868. //
  869. // Acquire the context swap lock, clear the processor set member in he old
  870. // process, set the processor member in the new process, and release the
  871. // context swap lock.
  872. //
  873. #if !defined(NT_UP)
  874. stq a0, SwA0(sp) // save new process address
  875. stq a1, SwA1(sp) // save old process address
  876. ldil a0, LockQueueContextSwapLock // set lock queue number
  877. bsr ra, KeAcquireQueuedSpinLock // acquire context swap lock
  878. bis v0, zero, t6 // save old IRQL
  879. GET_PROCESSOR_CONTROL_REGION_BASE // get PCR address
  880. ldq a3, SwA0(sp) // restore new process address
  881. ldq a1, SwA1(sp) // restore old process address
  882. ldl t0, PcSetMember(v0) // get processor set member mask
  883. ldq t1, PrActiveProcessors(a1) // get old processor sets
  884. ldq t2, PrActiveProcessors(a3) // get new processor sets
  885. bic t1, t0, t3 // clear member in old active set
  886. bis t2, t0, t4 // set member in new active set
  887. sll t0, 32, t5 // set member in new run on set
  888. bis t4, t5, t4 //
  889. stq t3, PrActiveProcessors(a1) // set old processor sets
  890. stq t4, PrActiveProcessors(a3) // set new processor sets
  891. #else
  892. bis a0, zero, a3 // copy new process address
  893. #endif
  894. LDP a0, PrDirectoryTableBase(a3) // get page directory PDE
  895. srl a0, PTE_PFN, a0 // isloate page frame number
  896. //
  897. // If the maximum address space number is zero, then assign ASN zero to
  898. // the new process.
  899. //
  900. ldl a1, KiMaximumAsn // get maximum ASN number
  901. ldil a2, TRUE // set ASN wrap indicator
  902. beq a1, 40f // if eq, only one ASN
  903. bis a1, zero, t3 // save maximum ASN number
  904. //
  905. // Check if a pending TB invalidate all is pending on the current processor.
  906. //
  907. #if !defined(NT_UP)
  908. lda t8, KiTbiaFlushRequest // get TBIA flush request mask address
  909. ldl t1, 0(t8) // get TBIA flush request mask
  910. and t1, t0, t2 // check if current processor request
  911. beq t2, 10f // if eq, no pending flush request
  912. bic t1, t0, t1 // clear processor member in mask
  913. stl t1, 0(t8) // set TBIA flush request mask
  914. #endif
  915. //
  916. // If the process sequence number matches the master sequence number then
  917. // use the process ASN. Otherwise, allocate a new ASN and check for wrap.
  918. // If ASN wrap occurs, then also increment the master sequence number.
  919. //
  920. 10: lda t9, KiMasterSequence // get master sequence number address
  921. ldq t4, 0(t9) // get master sequence number
  922. ldq t5, PrProcessSequence(a3) // get process sequence number
  923. ldl a1, PrProcessAsn(a3) // get process ASN
  924. xor t4, t5, a2 // check if sequence number matches
  925. beq a2, 30f // if eq, sequence number match
  926. lda t10, KiMasterAsn // get master ASN number address
  927. ldl a1, 0(t10) // get master ASN number
  928. addl a1, 1, a1 // increment master ASN number
  929. cmpult t3, a1, a2 // check for ASN wrap
  930. beq a2, 20f // if eq, ASN did not wrap
  931. addq t4, 1, t4 // increment master sequence number
  932. stq t4, 0(t9) // set master sequence number
  933. #if !defined(NT_UP)
  934. ldl t5, KeActiveProcessors // get active processor mask
  935. bic t5, t0, t5 // clear current processor member
  936. stl t5, 0(t8) // request flush on other processors
  937. #endif
  938. bis zero, zero, a1 // reset master ASN
  939. 20: stl a1, 0(t10) // set master ASN number
  940. stl a1, PrProcessAsn(a3) // set process ASN number
  941. stq t4, PrProcessSequence(a3) // set process sequence number
  942. #if !defined(NT_UP)
  943. ldq t5, PrActiveProcessors(a3) // get new processor sets
  944. zapnot t5, 0xf, t5 // clear run on processor set
  945. sll t5, 32, t3 // set run on set equal to active set
  946. bis t5, t3, t5 //
  947. stq t5, PrActiveProcessors(a3) // set new processor sets
  948. #endif
  949. //
  950. // Merge TBIA flush request with ASN wrap indicator.
  951. //
  952. 30: //
  953. #if !defined(NT_UP)
  954. bis t2, a2, a2 // merge TBIA indicators
  955. #endif
  956. //
  957. // a0 = pfn of new page directory base
  958. // a1 = new address space number
  959. // a2 = tbiap indicator
  960. //
  961. 40: SWAP_PROCESS_CONTEXT // swap address space
  962. //
  963. // Release context swap lock.
  964. //
  965. #if !defined(NT_UP)
  966. ldil a0, LockQueueContextSwapLock // set lock queue number
  967. bis t6, zero, a1 // set old IRQL value
  968. bsr ra, KeReleaseQueuedSpinLock // release dispatcher lock
  969. #endif
  970. ldq ra, SwRa(sp) // restore return address
  971. lda sp, SwapFrameLength(sp) // deallocate stack frame
  972. ret zero, (ra) // return
  973. .end KiSwapProcess