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.

744 lines
26 KiB

  1. // TITLE("Interval and Profile Clock Interrupts")
  2. //++
  3. //
  4. // Copyright (c) 1990 Microsoft Corporation
  5. // Copyright (c) 1992 Digital Equipment Corporation
  6. //
  7. // Module Name:
  8. //
  9. // clock.s
  10. //
  11. // Abstract:
  12. //
  13. // This module implements the code necessary to field and process the
  14. // interval and profile clock interrupts.
  15. //
  16. // Author:
  17. //
  18. // David N. Cutler (davec) 27-Mar-1990
  19. // Joe Notarangelo 06-Apr-1992
  20. //
  21. // Environment:
  22. //
  23. // Kernel mode only.
  24. //
  25. // Revision History:
  26. //
  27. //--
  28. #include "ksalpha.h"
  29. #if DBG
  30. //
  31. // KiDpcTimeout - This is the number of clock ticks that a single DPC can
  32. // consume. When a DPC crosses this threshold, a BreakPoint is issued
  33. //
  34. .globl KiDpcTimeout
  35. KiDpcTimeout:
  36. .long 110
  37. //
  38. // KiDpcTimeoutMsg - This is the message that gets displayed if the DPC
  39. // has exceeded KiDpcTimeout
  40. //
  41. .globl KiDpcTimeoutMsg
  42. KiDpcTimeoutMsg:
  43. .ascii "\n*** DPC routine > 1 sec --- This is not a break in KeUpdateRunTime\n"
  44. //
  45. // KiDpcTimeoutMsgLength - This is the length of the timeout message,
  46. // including the trailing NULL
  47. //
  48. .globl KiDpcTimeoutMsgLength
  49. KiDpcTimeoutMsgLength:
  50. .long 69
  51. #endif
  52. //++
  53. //
  54. // VOID
  55. // KeUpdateSystemTime (
  56. // IN ULONG TimeIncrement
  57. // )
  58. //
  59. // Routine Description:
  60. //
  61. // This routine is entered as the result of an interrupt generated by the
  62. // interval timer. Its function is to update the system time and check to
  63. // determine if a timer has expired.
  64. //
  65. // N.B. This routine is executed on a single processor in a multiprocess
  66. // system. The remainder of the processors only execute the quantum end
  67. // and runtime update code.
  68. //
  69. // Arguments:
  70. //
  71. // Time Increment (a0) - Supplies the time increment in 100ns units.
  72. //
  73. // Return Value:
  74. //
  75. // None.
  76. //
  77. //--
  78. LEAF_ENTRY(KeUpdateSystemTime)
  79. //
  80. // Update the interrupt time.
  81. //
  82. lda a2, KiTickOffset // get tick offset value
  83. ldl a3, 0(a2) //
  84. LDIP t8, SharedUserData // get shared user data address
  85. ldl t9, UsInterruptTime + 0(t8) // get low interrupt time
  86. ldl t10, UsInterruptTime + 4(t8) // get high interrupt time
  87. addl a0, t9, t9 // add time increment value
  88. cmpult t9, a0, t11 // compute carry
  89. addl t11, t10, t10 // add carry to high part
  90. stl t10, UsInterruptTime + 8(t8) // store high interrupt time
  91. stl t9, UsInterruptTime + 0(t8) // store low interrupt time
  92. #if !defined(NT_UP)
  93. mb //
  94. #endif
  95. stl t10, UsInterruptTime + 4(t8) // store high interrupt time
  96. zapnot t9, 15, t9 // set t9 = full 64 bits of
  97. sll t10, 32, t10 // interrupt time
  98. bis t9, t10, t9 //
  99. subq a3, a0, a3 // subtract time increment
  100. lda v0, KeTickCount // get tick count value
  101. ldq t6, 0(v0) //
  102. lda t0, KiTimerTableListHead // get base address of timer table
  103. stl a3, 0(a2) // store tick offset value
  104. bgt a3, 10f // if gt, tick not completed
  105. ldl a4, KeMaximumIncrement // get maximum increment value
  106. //
  107. // Update system time.
  108. //
  109. lda t1, KeTimeAdjustment // get time adjustment value
  110. ldl t1, 0(t1) //
  111. ldl t3, UsSystemTime + 0(t8) // get low system time
  112. ldl t4, UsSystemTime + 4(t8) // get high system time
  113. addl t1, t3, t3 // add time increment value
  114. cmpult t3, t1, t5 // compute carry
  115. addl t5, t4, t4 // add carry to high part
  116. stl t4, UsSystemTime + 8(t8) // store high system time
  117. stl t3, UsSystemTime + 0(t8) // store low system time
  118. #if !defined(NT_UP)
  119. mb //
  120. #endif
  121. stl t4, UsSystemTime + 4(t8) // store high system time
  122. //
  123. // Update the tick count.
  124. //
  125. addq t6, 1, t1 // increment tick count value
  126. stq t1, 0(v0) // store tick count value
  127. stl t1, UsTickCountLow(t8) // store low tick count value
  128. //
  129. // Compute next tick offset value.
  130. //
  131. addq a3, a4, a4 // add maximum increment to residue
  132. stl a4, 0(a2) // store tick offset value
  133. //
  134. // Check to determine if a timer has expired at the current hand value.
  135. //
  136. and t6, TIMER_TABLE_SIZE - 1, v0 // reduce to table table index
  137. #if defined(_AXP64_)
  138. sll v0, 4, t2 // compute timer table listhead address
  139. addq t2, t0, t2 //
  140. #else
  141. s8addl v0, t0, t2 // compute timer table listhead address
  142. #endif
  143. LDP t3, LsFlink(t2) // get address of first timer in list
  144. cmpeq t2, t3, t4 // compare fist with listhead address
  145. bne t4, 5f // if ne, no timer active
  146. //
  147. // Get the expiration time from the timer object.
  148. //
  149. // N.B. The offset to the timer list entry must be subtracted out of the
  150. // displacement calculation.
  151. //
  152. ldq t4,TiDueTime - TiTimerListEntry(t3) // get due time
  153. cmpule t4, t9, t5 // is expiration time <= system time
  154. bne t5, 20f // if ne, timer has expired
  155. //
  156. // Check to determine if a timer has expired at the next hand value.
  157. //
  158. 5: addq t6, 1, t6 // advance hand value to next entry
  159. 10: and t6, TIMER_TABLE_SIZE - 1, v0 // reduce to table table index
  160. #if defined(_AXP64_)
  161. sll v0, 4, t2 // compute timer table listhead address
  162. addq t2, t0, t2 //
  163. #else
  164. s8addl v0, t0, t2 // compute timer table listhead address
  165. #endif
  166. LDP t3, LsFlink(t2) // get address of first timer in list
  167. cmpeq t2, t3, t4 // compare fist with listhead address
  168. bne t4, 40f // if ne, no timer active
  169. //
  170. // Get the expiration time from the timer object.
  171. //
  172. ldq t4, TiDueTime - TiTimerListEntry(t3) // get due time
  173. cmpule t4, t9, t5 // is expiration time <= system time
  174. beq t5, 40f // if eq, timer has not expired
  175. //
  176. // Put timer expiration DPC in the system DPC list and initiate a dispatch
  177. // interrupt on the current processor.
  178. //
  179. 20: lda t2, KiTimerExpireDpc // get expiration DPC address
  180. DISABLE_INTERRUPTS // disable interrupts
  181. GET_PROCESSOR_CONTROL_BLOCK_BASE // get current prcb address
  182. lda t3, PbDpcListHead(v0) // get DPC listhead address
  183. lda t1, PbDpcLock(v0) // get address of spin lock
  184. #if !defined(NT_UP)
  185. 30: LDP_L t4, 0(t1) // get current lock value
  186. bis t1, zero, t5 // set ownership value
  187. bne t4, 50f // if ne, spin lock owned
  188. STP_C t5, 0(t1) // set spin lock owned
  189. beq t5, 50f // if eq, store conditional failed
  190. mb // synchronize memory access
  191. #endif
  192. LDP t4, DpLock(t2) // get DPC inserted state
  193. bne t4, 35f // if ne, DPC entry already inserted
  194. LDP t4, LsBlink(t3) // get address of last entry in list
  195. STP t1, DpLock(t2) // set DPC inserted state
  196. STP t6, DpSystemArgument1(t2) // set timer table hand value
  197. ADDP t2, DpDpcListEntry, t2 // compute address of DPC list entry
  198. STP t2, LsBlink(t3) // set address of new last entry
  199. STP t2, LsFlink(t4) // set next link in old last entry
  200. STP t3, LsFlink(t2) // set address of next entry
  201. STP t4, LsBlink(t2) // set address of previous entry
  202. ldl t5, PbDpcQueueDepth(v0) // get current DPC queue depth
  203. addl t5, 1, t7 // increment DPC queue depth
  204. stl t7, PbDpcQueueDepth(v0) // set updated DPC queue depth
  205. //
  206. // N.B. Since an interrupt must be active, simply set the software interrupt
  207. // request bit in the PRCB to request a dispatch interrupt directly from
  208. // the interrupt exception handler.
  209. //
  210. ldil t11, DISPATCH_INTERRUPT // get interrupt request level
  211. stl t11, PbSoftwareInterrupts(v0) // set interrupt request level
  212. 35: //
  213. #if !defined(NT_UP)
  214. mb // synchronize memory access
  215. STP zero, 0(t1) // set spin lock not owned
  216. #endif
  217. ENABLE_INTERRUPTS // enable interrupts
  218. //
  219. // Check to determine is a full tick has expired.
  220. //
  221. 40: ble a3, KeUpdateRunTime // if le, full tick expiration
  222. ret zero, (ra) // return
  223. //
  224. // Attempt to acquire the dpc lock failed.
  225. //
  226. #if !defined(NT_UP)
  227. 50: LDP t4, 0(t1) // get lock value
  228. beq t4, 30b // if eq, lock available
  229. br zero, 50b // retry
  230. #endif
  231. .end KeUpdateSystemTime
  232. //++
  233. //
  234. // VOID
  235. // KeUpdateRunTime (
  236. // VOID
  237. // )
  238. //
  239. // Routine Description:
  240. //
  241. // This routine is entered as the result of an interrupt generated by the
  242. // interval timer. Its function is to update the runtime of the current
  243. // thread, update the runtime of the current thread's process, and decrement
  244. // the current thread's quantum.
  245. //
  246. // N.B. This routine is executed on all processors in a multiprocess system.
  247. //
  248. // Arguments:
  249. //
  250. // None
  251. //
  252. // Return Value:
  253. //
  254. // None.
  255. //
  256. //--
  257. LEAF_ENTRY(KeUpdateRunTime)
  258. GET_CURRENT_THREAD // get current thread address
  259. bis v0, zero, t0 // save current thread address
  260. GET_PROCESSOR_CONTROL_BLOCK_BASE // get current prcb address
  261. bis v0, zero, t5 // save current prcb address
  262. LDP a0, PbInterruptTrapFrame(v0) // get trap frame address
  263. //
  264. // Update the current DPC rate.
  265. //
  266. // A running average of the DPC rate is used. The number of DPCs requested
  267. // in the previous tick is added to the current DPC rate and divided by two.
  268. // This becomes the new DPC rate.
  269. //
  270. ldl t1, PbDpcCount(t5) // get current DPC count
  271. ldl t6, PbLastDpcCount(t5) // get last DPC count
  272. subl t1, t6, t7 // compute difference
  273. ldl t2, PbDpcRequestRate(t5) // get old DPC request rate
  274. addl t7, t2, t3 // compute average
  275. srl t3, 1, t4 //
  276. stl t4, PbDpcRequestRate(t5) // store new DPC request rate
  277. stl t1, PbLastDpcCount(t5) // update last DPC count
  278. LDP t2, ThApcState + AsProcess(t0) // get current process address
  279. ldl t3, TrPsr(a0) // get saved processor status
  280. and t3, PSR_MODE_MASK, t6 // isolate previous mode
  281. bne t6, 30f // if ne, previous mode was user
  282. //
  283. // If a DPC is active, then increment the time spent executing DPC routines.
  284. // Otherwise, if the old IRQL is greater than DPC level, then increment the
  285. // time spent executing interrupt service routines. Otherwise, increment
  286. // the time spent in kernel mode for the current thread.
  287. //
  288. srl t3, PSR_IRQL, t6 // isolate previous IRQL
  289. ldl v0, PbDpcRoutineActive(t5) // get DPC active flag
  290. subl t6, DISPATCH_LEVEL, t6 // previous Irql - DPC level
  291. blt t6, 20f // if lt, charge against thread
  292. lda t8, PbInterruptTime(t5) // compute interrupt time address
  293. bgt t6, 10f // if gt, increment interrupt time
  294. lda t8, PbDpcTime(t5) // compute DPC time address
  295. beq v0, 20f // if eq, not executing DPC
  296. #if DBG
  297. //
  298. // On a checked build, increment the DebugDpcTime count and see if this
  299. // has exceeded the value of KiDpcTimeout. If it has, then we need to
  300. // print a message and issue a breakpoint (if possible)
  301. //
  302. ldl t9, PbDebugDpcTime(t5) // load current time in DPC
  303. addl t9, 1, t9 // another tick occured
  304. ldl t10, KiDpcTimeout // What is the timeout value?
  305. cmpule t9, t10, t11 // T11=1 if tick <= timeout
  306. bne t11, 5f // if ne, then time is okay
  307. lda a0, KiDpcTimeoutMsg // load the timeout message address
  308. ldl a1, KiDpcTimeoutMsgLength // load the timeout message length
  309. BREAK_DEBUG_PRINT // Print the message
  310. BREAK_DEBUG_STOP // Enter the debugger
  311. bis zero, zero, t9 // Clear the time in DPC
  312. 5: stl t9, PbDebugDpcTime(t5) // store current time in DPC
  313. #endif
  314. //
  315. // Update the time spent executing DPC or interrupt level
  316. //
  317. // t8 = address of time to increment
  318. //
  319. 10: ldl t11, 0(t8) // get processor time
  320. addl t11, 1, t11 // increment processor time
  321. stl t11, 0(t8) // update processor time
  322. lda t6, PbKernelTime(t5) // compute address of kernel time
  323. br zero, 45f // update kernel time
  324. //
  325. // Update the time spent in kernel mode for the current thread and the current
  326. // thread's process.
  327. //
  328. 20: ldl t11, ThKernelTime(t0) // get kernel time
  329. addl t11, 1, t11 // increment kernel time
  330. stl t11, ThKernelTime(t0) // store updated kernel time
  331. lda t2, PrKernelTime(t2) // compute process kernel time address
  332. lda t6, PbKernelTime(t5) // compute processor kernel time addr
  333. br zero, 40f // join comon code
  334. //
  335. // Update the time spend in user mode for the current thread and the current
  336. // thread's process.
  337. //
  338. 30: ldl t11, ThUserTime(t0) // get user time
  339. addl t11, 1, t11 // increment user time
  340. stl t11, ThUserTime(t0) // store updated user time
  341. lda t2, PrUserTime(t2) // compute process user time address
  342. lda t6, PbUserTime(t5) // compute processor user time address
  343. //
  344. // Update the time spent in kernel/user mode for the current thread's process.
  345. //
  346. 40: //
  347. #if !defined(NT_UP)
  348. ldl_l t11, 0(t2) // get process time
  349. addl t11, 1, t11 // increment process time
  350. stl_c t11, 0(t2) // store updated process time
  351. beq t11, 41f // if eq, store conditional failed
  352. mb // synchronize subsequent reads
  353. #else
  354. ldl t11,0(t2) // get process time
  355. addl t11, 1, t11 // increment process time
  356. stl t11,0(t2) // store updated process time
  357. #endif
  358. //
  359. // A DPC is not active. If there are DPCs in the DPC queue and a DPC
  360. // interrupt has not been requested, request a dispatch interrupt in
  361. // order to initiate the batch processing of the pending DPCs in the
  362. // DPC queue.
  363. //
  364. // N.B. Since an interrupt must be active, the software interrupt request
  365. // bit in the PRCB can be set to request a dispatch interrupt directly from
  366. // the interrupt exception handler.
  367. //
  368. // Pushing DPCs from the clock interrupt indicates that the current maximum
  369. // DPC queue depth is too high. If the DPC rate does not exceed the ideal
  370. // rate, decrement the maximum DPC queue depth and
  371. // reset the threshold to its original value.
  372. //
  373. ldl t1, PbDpcQueueDepth(t5) // get current queue depth
  374. beq t1, 45f // skip if queue is empty
  375. ldl t2, PbDpcInterruptRequested(t5) // get dpc interrupt request flag
  376. bne t2, 45f // skip if flag is set
  377. ldil a0, DISPATCH_INTERRUPT // set software interrupt request
  378. stl a0, PbSoftwareInterrupts(t5) //
  379. ldl t3, PbMaximumDpcQueueDepth(t5) // get current DPC queue depth
  380. subl t3, 1, t4 // decrement
  381. ldl t2, PbDpcRequestRate(t5) // get old DPC request rate
  382. ldl t1, KiIdealDpcRate // get ideal DPC rate
  383. cmpult t2, t1, t2 // compare current with ideal
  384. ldl t1, KiAdjustDpcThreshold // get system threshold default
  385. stl t1, PbAdjustDpcThreshold(t5) // reset processor threshold default
  386. beq t4, 50f // if queue depth==0, skip decrement
  387. beq t2, 50f // if rate not lt ideal rate, skip decrement
  388. stl t4, PbMaximumDpcQueueDepth(t5) // set current DPC queue depth
  389. br zero, 50f // rejoin common code
  390. //
  391. // There is no need to push a DPC from the clock interrupt. This indicates that
  392. // the current maximum DPC queue depth may be too low. Decrement the threshold
  393. // indicator, and if the new threshold is zero, and the current maximum queue
  394. // depth is less than the maximum, increment the maximum DPC queue
  395. // depth.
  396. //
  397. 45: ldl t1, PbAdjustDpcThreshold(t5) // get current threshold
  398. subl t1, 1, t2 // decrement threshold
  399. stl t2, PbAdjustDpcThreshold(t5) // update current threshold
  400. bne t2, 50f // if threshold nez, skip
  401. ldl t1, KiAdjustDpcThreshold // get system threshold default
  402. stl t1, PbAdjustDpcThreshold(t5) // reset processor threshold default
  403. ldl t3, PbMaximumDpcQueueDepth(t5) // get current DPC queue depth
  404. ldl t1, KiMaximumDpcQueueDepth // get maximum DPC queue depth
  405. cmpult t3, t1, t2 // compare
  406. beq t2, 50f // if current not lt maximum, skip
  407. addl t3, 1, t4 // increment queue depth
  408. stl t4, PbMaximumDpcQueueDepth(t5) // update current DPC queue depth
  409. //
  410. // Update the time spent in kernel/user mode for the current processor.
  411. //
  412. // t5 = pointer to processor time to increment
  413. //
  414. 50: ldl t11, 0(t6) // get processor time
  415. addl t11, 1, t11 // increment processor time
  416. stl t11, 0(t6) // store updated processor time
  417. //
  418. // If the current thread is not the idle thread, decrement its
  419. // quantum and check to determine if a quantum end has occurred.
  420. //
  421. LDP t6, PbIdleThread(t5) // get address of idle thread
  422. cmpeq t6, t0, t7 // check if idle thread running
  423. bne t7, 60f // if ne, idle thread running
  424. LoadByte(t7, ThQuantum(t0)) // get current thread quantum
  425. sll t7, 56, t9 //
  426. sra t9, 56, t7 //
  427. subl t7, CLOCK_QUANTUM_DECREMENT, t7 // decrement quantum
  428. StoreByte(t7, ThQuantum(t0)) // store thread quantum
  429. bgt t7, 60f // if gtz, quantum remaining
  430. //
  431. // Put processor specific quantum end DPC in the system DPC list and initiate
  432. // a dispatch interrupt on the current processor.
  433. //
  434. // N.B. Since an interrupt must be active, simply set the software interrupt
  435. // request bit in the PRCB to request a dispatch interrupt directly from
  436. // the interrupt exception handler.
  437. //
  438. ldil a0, DISPATCH_INTERRUPT // set interrupt request mask
  439. stl a0, PbSoftwareInterrupts(t5) // request software interrupt
  440. stl a0, PbQuantumEnd(t5) // set quantum end indicator
  441. 60: ret zero, (ra) // return
  442. //
  443. // Atomic increment of user/kernel time failed.
  444. //
  445. #if !defined(NT_UP)
  446. 41: br zero, 40b // retry atomic increment
  447. #endif
  448. .end KeUpdateRunTime
  449. //++
  450. //
  451. // VOID
  452. // KeProfileInterrupt (
  453. // VOID
  454. // )
  455. //
  456. // VOID
  457. // KeProfileInterruptWithSource (
  458. // IN KPROFILE_SOURCE ProfileSource
  459. // )
  460. //
  461. // VOID
  462. // KiProfileInterrupt(
  463. // IN KPROFILE_SOURCE ProfileSource,
  464. // IN PKTRAP_FRAME TrapFrame
  465. // )
  466. //
  467. // Routine Description:
  468. //
  469. // This routine is entered as the result of an interrupt generated by the
  470. // profile timer. Its function is to update the profile information for
  471. // the currently active profile objects.
  472. //
  473. // N.B. This routine is executed on all processors in a multiprocess system.
  474. //
  475. // Arguments:
  476. //
  477. // ProfileSource (a0) - Supplies the source of the profile interrupt
  478. // KeProfileInterrupt is an alternate entry for backwards
  479. // compatibility that sets the source to zero (ProfileTime)
  480. //
  481. // Return Value:
  482. //
  483. // None.
  484. //
  485. //--
  486. .struct 0
  487. PfS0: .space 8 // saved integer register s0
  488. PfRa: .space 8 // return address
  489. .space 2 * 8 // profile frame length
  490. ProfileFrameLength:
  491. NESTED_ENTRY(KeProfileInterrupt, ProfileFrameLength, zero)
  492. bis zero, zero, a0 // set profile source to ProfileTime
  493. ALTERNATE_ENTRY(KeProfileInterruptWithSource)
  494. GET_PROCESSOR_CONTROL_BLOCK_BASE // get current prcb address
  495. LDP a1, PbInterruptTrapFrame(v0) // get trap frame address
  496. ALTERNATE_ENTRY(KiProfileInterrupt)
  497. lda sp, -ProfileFrameLength(sp) // allocate stack frame
  498. stq ra, PfRa(sp) // save return address
  499. #if !defined(NT_UP)
  500. stq s0, PfS0(sp) // save integer register s0
  501. #endif
  502. PROLOGUE_END
  503. //
  504. // Acquire profile lock.
  505. //
  506. #if !defined(NT_UP)
  507. lda s0, KiProfileLock // get address of profile lock
  508. 10: LDP_L t0, 0(s0) // get current lock value
  509. bis s0, zero, t1 // set ownership value
  510. bne t0, 15f // if ne, spin lock owned
  511. STP_C t1, 0(s0) // set spin lock owned
  512. beq t1, 15f // if eq, store conditional failed
  513. mb // synchronize memory access
  514. #endif
  515. GET_CURRENT_THREAD // get current thread address
  516. LDP a2, ThApcState + AsProcess(v0) // get current process address
  517. ADDP a2, PrProfileListHead, a2 // compute profile listhead address
  518. bsr ra, KiProcessProfileList // process profile list
  519. lda a2, KiProfileListHead // get system profile listhead address
  520. bsr ra, KiProcessProfileList // process profile list
  521. #if !defined(NT_UP)
  522. mb // synchronize memory access
  523. STP zero, 0(s0) // set spin lock not owned
  524. ldq s0, PfS0(sp) // restore s0
  525. #endif
  526. ldq ra, PfRa(sp) // restore return address
  527. lda sp, ProfileFrameLength(sp) // deallocate stack frame
  528. ret zero, (ra) // return
  529. //
  530. // Acquire profile lock failed.
  531. //
  532. #if !defined(NT_UP)
  533. 15: LDP t0, 0(s0) // get current lock value
  534. beq t0, 10b // if eq, lock available
  535. br zero, 15b // spin in cache until lock ready
  536. #endif
  537. .end KeProfileInterrupt
  538. //++
  539. //
  540. // VOID
  541. // KiProcessProfileList (
  542. // IN KPROFILE_SOURCE Source,
  543. // IN PKTRAP_FRAME TrapFrame,
  544. // IN PLIST_ENTRY ListHead
  545. // )
  546. //
  547. // Routine Description:
  548. //
  549. // This routine is called to process a profile list.
  550. //
  551. // Arguments:
  552. //
  553. // Source (a1) - Supplies profile source to match
  554. //
  555. // TrapFrame (a0) - Supplies a pointer to a trap frame.
  556. //
  557. // ListHead (a2) - Supplies a pointer to a profile list.
  558. //
  559. // Return Value:
  560. //
  561. // None.
  562. //
  563. //--
  564. LEAF_ENTRY(KiProcessProfileList)
  565. LDP a3, LsFlink(a2) // get address of next entry
  566. cmpeq a2, a3, t0 // end of list ?
  567. bne t0, 30f // if ne, end of list
  568. LDP t0, TrFir(a1) // get interrupt PC address
  569. GET_PROCESSOR_CONTROL_REGION_BASE // get current pcr address
  570. ldl t6, PcSetMember(v0) // get processor member
  571. //
  572. // Scan profile list and increment profile buckets as appropriate.
  573. //
  574. 10: LDP t1, PfRangeBase - PfProfileListEntry(a3) // get base of range
  575. LDP t2, PfRangeLimit - PfProfileListEntry(a3) // get limit of range
  576. ldl t4, PfSource - PfProfileListEntry(a3) // get source
  577. ldl t7, PfAffinity - PfProfileListEntry(a3) // get affinity
  578. zapnot t4, 3, t4 // source is a SHORT
  579. cmpeq t4, a0, t5 // check against profile source
  580. and t7, t6, v0 // check against processor
  581. beq t5, 20f // if ne, profile source doesn't match
  582. beq v0, 20f // if ne, processor doesn't match
  583. cmpult t0, t1, v0 // check against range base
  584. cmpult t0, t2, t3 // check against range limit
  585. bne v0, 20f // if ne, less than range base
  586. beq t3, 20f // if eq, not less than range limit
  587. SUBP t0, t1, t1 // compute offset in range
  588. ldl t2, PfBucketShift - PfProfileListEntry(a3) // get shift count
  589. LDP v0, PfBuffer - PfProfileListEntry(a3) // profile buffer address
  590. zap t1, 0xf0, t1 // force bucket offset to 32bit unit
  591. srl t1, t2, t3 // compute bucket offset
  592. bic t3, 0x3, t3 // clear low order offset bits
  593. ADDP v0, t3, t3 // compute bucket address
  594. ldl v0, 0(t3) // increment profile bucket
  595. addl v0, 1, v0 //
  596. stl v0, 0(t3) //
  597. 20: LDP a3, LsFlink(a3) // get address of next entry
  598. cmpeq a2, a3, t1 // end of list?
  599. beq t1, 10b // if eq[false], more entries
  600. 30: ret zero, (ra) // return
  601. .end KiProcessProfileList