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.

928 lines
29 KiB

  1. title "Interval Clock Interrupt"
  2. ;++
  3. ;
  4. ; Copyright (c) 1989 Microsoft Corporation
  5. ;
  6. ; Module Name:
  7. ;
  8. ; clockint.asm
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module implements the code necessary to field and process the
  13. ; interval clock interrupt.
  14. ;
  15. ; Author:
  16. ;
  17. ; Shie-Lin Tzong (shielint) 12-Jan-1990
  18. ;
  19. ; Environment:
  20. ;
  21. ; Kernel mode only.
  22. ;
  23. ; Revision History:
  24. ;
  25. ; bryanwi 20-Sep-90
  26. ;
  27. ; Add KiSetProfileInterval, KiStartProfileInterrupt,
  28. ; KiStopProfileInterrupt procedures.
  29. ; KiProfileInterrupt ISR.
  30. ; KiProfileList, KiProfileLock are delcared here.
  31. ;
  32. ; shielint 10-Dec-90
  33. ; Add performance counter support.
  34. ; Move system clock to irq8, ie we now use RTC to generate system
  35. ; clock. Performance count and Profile use timer 1 counter 0.
  36. ; The interval of the irq0 interrupt can be changed by
  37. ; KiSetProfileInterval. Performance counter does not care about the
  38. ; interval of the interrupt as long as it knows the rollover count.
  39. ; Note: Currently I implemented 1 performance counter for the whole
  40. ; i386 NT. It works on UP and SystemPro.
  41. ;
  42. ;--
  43. .386p
  44. .xlist
  45. KERNELONLY equ 1
  46. include ks386.inc
  47. include callconv.inc ; calling convention macros
  48. include i386\kimacro.inc
  49. include mac386.inc
  50. .list
  51. EXTRNP Kei386EoiHelper
  52. EXTRNP HalRequestSoftwareInterrupt,1,IMPORT,FASTCALL
  53. EXTRNP _HalEndSystemInterrupt,2,IMPORT
  54. extrn _KeTimeIncrement:DWORD
  55. extrn _KeMaximumIncrement:DWORD
  56. extrn _KeTickCount:DWORD
  57. extrn _KeTimeAdjustment:DWORD
  58. extrn _KiAdjustDpcThreshold:DWORD
  59. extrn _KiIdealDpcRate:DWORD
  60. extrn _KiMaximumDpcQueueDepth:DWORD
  61. extrn _KiTickOffset:DWORD
  62. extrn _KiTimerTableListHead:DWORD
  63. extrn _KiTimerExpireDpc:DWORD
  64. extrn _KiTimeUpdateNotifyRoutine:DWORD
  65. extrn _KiProfileListHead:DWORD
  66. extrn _KiProfileLock:DWORD
  67. extrn _KiProfileInterval:DWORD
  68. extrn _KdDebuggerEnabled:BYTE
  69. EXTRNP _DbgBreakPoint
  70. EXTRNP _DbgBreakPointWithStatus,1
  71. EXTRNP _KdPollBreakIn
  72. EXTRNP _KiDeliverApc,3
  73. extrn _KeI386MachineType:DWORD
  74. extrn _PPerfGlobalGroupMask:DWORD
  75. EXTRNP PerfProfileInterrupt,2,,FASTCALL
  76. if DBG
  77. extrn _DbgPrint:near
  78. extrn _KiDPCTimeout:DWORD
  79. extrn _MsgDpcTimeout:BYTE
  80. endif
  81. ifdef NT_UP
  82. LOCK_INC equ inc
  83. else
  84. LOCK_INC equ lock inc
  85. endif
  86. _DATA SEGMENT DWORD PUBLIC 'DATA'
  87. public ProfileCount
  88. ProfileCount DD 0
  89. _DATA ends
  90. page ,132
  91. subttl "Update System Time"
  92. _TEXT$00 SEGMENT DWORD PUBLIC 'CODE'
  93. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  94. ;++
  95. ;
  96. ; VOID
  97. ; KeUpdateSystemTime (
  98. ; IN KIRQL PreviousIrql,
  99. ; IN KTRAP_FRAME TrapFrame
  100. ; )
  101. ;
  102. ; Routine Description:
  103. ;
  104. ; This routine is entered as the result of an interrupt generated by CLOCK2.
  105. ; Its function is to update the system time and check to determine if a timer
  106. ; has expired.
  107. ;
  108. ; N.B. This routine is executed on a single processor in a multiprocess
  109. ; system. The remainder of the processors only execute the quantum end
  110. ; and runtime update code.
  111. ;
  112. ; N.B. This routine is not called, but directly jumped to. Thus, there
  113. ; is no return address. It returns via the INTERRUPT_EXIT macro.
  114. ;
  115. ; Arguments:
  116. ;
  117. ; PreviousIrql (esp) - supplies previous irql of system
  118. ;
  119. ; HardwareVector (esp+4) - supplies hardware vector for EndSystemInterrupt
  120. ;
  121. ; TrapFrame (esp+8) - supplies base of trap frame
  122. ;
  123. ; EAX is the TimeIncrement value
  124. ;
  125. ; EBP is a pointer to the trap frame
  126. ;
  127. ;
  128. ; Environment:
  129. ;
  130. ; IRQL = CLOCK_LEVEL
  131. ;
  132. ; Return Value:
  133. ;
  134. ; None.
  135. ;
  136. ;--
  137. cPublicProc _KeUpdateSystemTime ,0
  138. .FPO (2, 0, 0, 0, 0, 1) ; treat params as locals since functions is JMPed too
  139. if DBG
  140. cmp byte ptr PCR[PcPrcbData+PbSkipTick], 0
  141. jnz kust_skiptick
  142. endif
  143. ;
  144. ; Update interrupt time.
  145. ;
  146. ; N.B. The interrupt time is updated in a very strict manner so that an
  147. ; interlock does not have to be used in an MP system to read time.
  148. ;
  149. mov ecx,USER_SHARED_DATA ; set address of user shared data
  150. mov edi,[ecx].UsInterruptTime+0 ; get low interrupt time
  151. mov esi,[ecx].UsInterruptTime+4 ; get high interrupt time
  152. add edi,eax ; add time increment
  153. adc esi,0 ; propagate carry
  154. mov [ecx].UsInterruptTime+8,esi ; store high 2 interrupt time
  155. mov [ecx].UsInterruptTime+0,edi ; store low interrupt time
  156. mov [ecx].UsInterruptTime+4,esi ; store high 1 interrupt time
  157. sub _KiTickOffset,eax ; subtract time increment
  158. mov eax,_KeTickCount+0 ; get low tick count
  159. mov ebx,eax ; copy low tick count
  160. jg kust10 ; if greater, not complete tick
  161. ;
  162. ; Update system time.
  163. ;
  164. ; N.B. The system time is updated in a very strict manner so that an
  165. ; interlock does not have to be used in an MP system to read time.
  166. ;
  167. mov ebx,USER_SHARED_DATA ; set address of user shared data
  168. mov ecx,[ebx].UsSystemTime+0 ; get low interrupt time
  169. mov edx,[ebx].UsSystemTime+4 ; get high interrupt time
  170. add ecx,_KeTimeAdjustment ; add time increment
  171. adc edx,0 ; propagate carry
  172. mov [ebx].UsSystemTime+8,edx ; store high 2 interrupt time
  173. mov [ebx].UsSystemTime+0,ecx ; store low interrupt time
  174. mov [ebx].UsSystemTime+4,edx ; store high 1 interrupt time
  175. mov ebx,eax ; restore low tick count
  176. ;
  177. ; Update tick count.
  178. ;
  179. ; N.B. The tick count is updated in a very strict manner so that an
  180. ; interlock does not have to be used in an MP system to read count.
  181. ;
  182. mov ecx,eax ; copy low tick count
  183. mov edx,_KeTickCount+4 ; get high tick count
  184. add ecx,1 ; increment tick count
  185. adc edx,0 ; propagate carry
  186. mov _KeTickCount+8,edx ; store high 2 tick count
  187. mov _KeTickCount+0,ecx ; store low tick count
  188. mov _KeTickCount+4,edx ; store high 1 tick count
  189. mov USERDATA[UsTickCountLow], ecx
  190. if 0
  191. ; debug code
  192. push eax
  193. mov edx, esi
  194. mov eax, edi ; (eax:edx) = InterruptTime
  195. mov ecx, _KeMaximumIncrement
  196. div ecx
  197. cmp al, bl ; same bucket?
  198. je short @f
  199. int 3 ; no - stop
  200. @@:
  201. pop eax
  202. endif
  203. ;
  204. ; Check to determine if a timer has expired.
  205. ; (edi:esi) = KiInterruptTime
  206. ; (eax) = KeTickCount.LowPart
  207. ; (ebx) = KeTickCount.LowPart
  208. ;
  209. and eax,TIMER_TABLE_SIZE-1 ; isolate current hand value
  210. lea ecx,_KiTimerTableListHead[eax*8] ; get listhead addrees
  211. mov edx,[ecx] ; get first entry address
  212. cmp ecx,edx ; check if list is empry
  213. je short kust5 ; if equal, list is empty
  214. cmp esi,[edx].TiDueTime.TmHighTime-TiTimerListEntry ; compare high
  215. jb short kust5 ; if below, timer has not expired
  216. ja short kust15 ; if above, timer has expired
  217. cmp edi,[edx].TiDueTime.TmLowTime-TiTimerListEntry ; compare low
  218. jae short kust15 ; if above or equal, time has expired
  219. kust5: inc eax ; advance hand value to next entry
  220. inc ebx
  221. ;
  222. ; Check to determine if a timer has expired.
  223. ; (edi:esi) = KiInterruptTime
  224. ; (eax) = bucket
  225. ; (ebx) = KeTickCount.LowPart
  226. ;
  227. kust10: and eax,TIMER_TABLE_SIZE-1 ; isolate current hand value
  228. lea ecx,_KiTimerTableListHead[eax*8] ; get listhead addrees
  229. mov edx,[ecx] ; get first entry address
  230. cmp ecx,edx ; check if list is empry
  231. je kustxx ; if equal, list is empty
  232. cmp esi,[edx].TiDueTime.TmHighTime-TiTimerListEntry ; compare high
  233. jb kustxx ; if below, timer has not expired
  234. ja short kust15 ; if above, timer has expired
  235. cmp edi,[edx].TiDueTime.TmLowTime-TiTimerListEntry ; compare low
  236. jb kustxx ; if below, timer has not expired
  237. kust15:
  238. ;
  239. ; Timer has expired, put timer expiration DPC in the current processor's DPC
  240. ; queue.
  241. ;
  242. ; (ebx) = KeTickCount.LowPart
  243. ;
  244. mov ecx,PCR[PcPrcb] ; get processor control block address
  245. lea eax,_KiTimerExpireDpc+DpDpcListEntry ; get list entry address
  246. lea edx,[ecx]+PbDpcLock ; get DPC lock address
  247. cmp dword ptr [eax]+(DpLock-DpDpcListEntry), 0H ; check if inserted
  248. jnz kustxx ; if nz, DPC already inserted
  249. kust20: cli
  250. ACQUIRE_SPINLOCK edx, kust60
  251. inc dword ptr [ecx].PbDpcQueueDepth ; increment DPC queue depth
  252. mov dword ptr [eax]+(DpLock-DpDpcListEntry), edx ; set lock address
  253. mov [eax]+(DpSystemArgument1-DpDpcListEntry),ebx ; pass tick count
  254. add ecx,PbDpcListHead ; compute DPC listhead address
  255. mov ebx,[ecx]+LsBlink ; get address of last entry in list
  256. mov [ecx]+LsBlink, eax ; set new address of last entry
  257. mov [ebx]+LsFlink, eax ; set forward link in old last entry
  258. mov [eax]+LsFlink, ecx ; set forward link in new last entry
  259. mov [eax]+LsBlink, ebx ; set backward link in new last entry
  260. RELEASE_SPINLOCK edx
  261. sti ; enable interrupt
  262. ; request dispatch interrupt
  263. mov ecx, DISPATCH_LEVEL
  264. fstCall HalRequestSoftwareInterrupt
  265. kustxx:
  266. if DEVL
  267. cmp _KdDebuggerEnabled, 0
  268. jnz short kust45
  269. kust30:
  270. endif
  271. cmp _KiTickOffset,0 ; check if full tick
  272. jg short Kust40 ; if not less, not a full tick
  273. mov eax,_KeMaximumIncrement ; get maximum time incrmeent
  274. add _KiTickOffset,eax ; add maximum tine to residue
  275. ;
  276. ; call KeUpdateRunTime to do the acutal work
  277. ;
  278. ; TOS const PreviousIrql
  279. push [esp]
  280. call _KeUpdateRunTime@4
  281. ;
  282. ; Do interrupt exit processing
  283. ;
  284. INTERRUPT_EXIT
  285. kust40:
  286. inc dword ptr PCR[PcPrcbData+PbInterruptCount]
  287. INTERRUPT_EXIT
  288. if DEVL
  289. kust45:
  290. stdCall _KdPollBreakIn
  291. or al,al
  292. jz short kust30
  293. stdCall _DbgBreakPointWithStatus,<DBG_STATUS_CONTROL_C>
  294. jmp short kust30
  295. endif
  296. if DBG
  297. kust_skiptick:
  298. mov byte ptr PCR[PcPrcbData+PbSkipTick], 0
  299. jmp short kust40
  300. endif
  301. ;
  302. ; Lock is currently owned; spin until free and then attempt to acquire
  303. ; lock again.
  304. ;
  305. ALIGN 4
  306. kust60: sti ; spin with interrupts enabled
  307. SPIN_ON_SPINLOCK edx, kust20,,DbgMp
  308. stdENDP _KeUpdateSystemTime
  309. page ,132
  310. subttl "Update Thread and Process Runtime"
  311. ;++
  312. ;
  313. ; Routine Description:
  314. ;
  315. ; This routines does the actual work to update the runtime of the current
  316. ; thread, update the runtime of the current thread's process, and
  317. ; decrement the current thread's quantum.
  318. ;
  319. ; It also updates the system global counters for user and kernel mode time.
  320. ;
  321. ; It increments InterruptCount so that clock ticks get counted as
  322. ; interrupts.
  323. ;
  324. ; Arguments:
  325. ;
  326. ; esp+4 constant PreviousIrql
  327. ;
  328. ; ebp MUST point to the machine state frame.
  329. ;
  330. ; Return Value:
  331. ;
  332. ; None.
  333. ;
  334. ;--
  335. cPublicProc _KeUpdateRunTime ,1
  336. cPublicFpo 1, 1
  337. mov eax, PCR[PcSelfPcr]
  338. if DBG
  339. cmp byte ptr [eax]+PcPrcbData+PbSkipTick, 0
  340. jnz kutp_skiptick
  341. endif
  342. push ebx ; we will destroy ebx
  343. inc dword ptr [eax]+PcPrcbData+PbInterruptCount
  344. mov ebx, [eax]+PcPrcbData+PbCurrentThread ; (ebx)->current thread
  345. mov ecx, ThApcState+AsProcess[ebx]
  346. ; (ecx)->current thread's process
  347. test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
  348. jne Kutp20 ; if ne, user mode
  349. test byte ptr [ebp]+TsSegCs, MODE_MASK ; test if prev mode was kernel
  350. jne Kutp20 ; if ne, user mode
  351. ;
  352. ; Update the total time spent in kernel mode
  353. ;
  354. mov edx, 0 ; set kernel mode
  355. inc dword ptr [eax].PcPrcbData.PbKernelTime
  356. cmp byte ptr [esp+8], DISPATCH_LEVEL
  357. jc short Kutp4 ; OldIrql<2, then kernel
  358. ja short Kutp3 ; OldIrql>2, then interrupt
  359. cmp dword ptr PCR[PcPrcbData.PbDpcRoutineActive], 0
  360. jz short Kutp4 ; Executing Dpc?, no then thread time
  361. inc dword ptr [eax].PcPrcbData.PbDpcTime
  362. if DBG
  363. ;
  364. ; Check for dpcs which run for too long
  365. ;
  366. inc dword ptr [eax].PcPrcbData.PbDebugDpcTime
  367. mov edx, _KiDPCTimeout
  368. cmp dword ptr [eax].PcPrcbData.PbDebugDpcTime, edx
  369. jc Kutp51 ; Jump if not over limit
  370. ;
  371. ; Dpc time has exceeded the allowed quanta
  372. ;
  373. push offset FLAT:_MsgDpcTimeout ; push message address
  374. call _DbgPrint ; print debug message
  375. add esp, 1 * 4 ; remove arguments from stack
  376. cmp _KdDebuggerEnabled, 0 ; check if debugger enabled
  377. je short Kutp6 ; if eq, no debugger, continue
  378. stdCall _DbgBreakPoint ; break into debugger
  379. Kutp6: mov eax, PCR[PcSelfPcr] ; restore PCR address
  380. mov dword ptr [eax].PcPrcbData.PbDebugDpcTime, 0 ; Reset Time
  381. endif
  382. jmp Kutp51
  383. ALIGN 4
  384. Kutp3:
  385. ;
  386. ; Update the time spent at interrupt time for this processor
  387. ;
  388. inc dword ptr [eax].PcPrcbData.PbInterruptTime
  389. jmp Kutp51
  390. ALIGN 4
  391. Kutp4:
  392. ;
  393. ; Update the time spent in kernel mode for the current thread and the current
  394. ; thread's process.
  395. ;
  396. inc dword ptr [ebx]+ThKernelTime
  397. LOCK_INC dword ptr [ecx]+PrKernelTime
  398. jmp Kutp50
  399. ;
  400. ; Update total time spent in user mode
  401. ;
  402. ALIGN 4
  403. Kutp20:
  404. mov edx, 1 ; set user mode
  405. inc dword ptr [eax].PcPrcbData.PbUserTime
  406. ;
  407. ; Update the time spend in user mode for the current thread and the current
  408. ; thread's process.
  409. ;
  410. inc dword ptr [ebx]+ThUserTime
  411. LOCK_INC dword ptr [ecx]+PrUserTime
  412. ;
  413. ; Notify registered callout routine of update time.
  414. ;
  415. ; N.B. The register edx contains the processor mode.
  416. ;
  417. ALIGN 4
  418. Kutp50: ;
  419. ifndef NT_UP
  420. cmp _KiTimeUpdateNotifyRoutine, 0 ; check for callout routine
  421. je short Kutp51 ; if eq, no callout routine registered
  422. mov ecx, [ebx].EtCid.CidUniqueThread ; set current thread unique id
  423. call [_KiTimeUpdateNotifyRoutine] ; notify callout routine
  424. mov eax, PCR[PcSelfPcr] ; restore PCR address
  425. endif
  426. ;
  427. ; Update the DPC request rate which is computed as the average between
  428. ; the previous rate and the current rate.
  429. ;
  430. ALIGN 4
  431. Kutp51: mov ecx, [eax].PcPrcbData.PbDpcCount ; get current DPC count
  432. mov edx, [eax].PcPrcbData.PbDpcLastCount ; get last DPC count
  433. mov [eax].PcPrcbData.PbDpcLastCount, ecx ; set last DPC count
  434. sub ecx, edx ; compute count during interval
  435. add ecx, [eax].PcPrcbData.PbDpcRequestRate ; compute sum
  436. shr ecx, 1 ; average current and last
  437. mov [eax].PcPrcbData.PbDpcRequestRate, ecx ; set new DPC request rate
  438. ;
  439. ; If the current DPC queue depth is not zero, a DPC routine is not active,
  440. ; and a DPC interrupt has not been requested, then request a dispatch
  441. ; interrupt, decrement the maximum DPC queue depth, and reset the threshold
  442. ; counter if appropriate.
  443. ;
  444. cmp dword ptr [eax].PcPrcbData.PbDpcQueueDepth, 0 ; check queue depth
  445. je short Kutp53 ; if eq, DPC queue depth is zero
  446. cmp dword ptr [eax].PcPrcbData.PbDpcRoutineActive, 0 ; check if DPC active
  447. jne short Kutp53 ; if ne, DPC routine active
  448. cmp dword ptr [eax].PcPrcbData.PbDpcInterruptRequested, 0 ; check if interrupt
  449. jne short Kutp53 ; if ne, DPC routine active
  450. mov ecx, DISPATCH_LEVEL ; request a dispatch interrupt
  451. fstCall HalRequestSoftwareInterrupt ;
  452. mov eax, PCR[PcSelfPcr] ; restore address of current PCR
  453. mov ecx, [eax].PcPrcbData.PbDpcRequestRate ; get DPC request rate
  454. mov edx, _KiAdjustDpcThreshold ; reset initial threshold counter
  455. mov [eax].PcPrcbData.PbAdjustDpcThreshold, edx ;
  456. cmp ecx, _KiIdealDpcRate ; test if current rate less than ideal
  457. jge short Kutp55 ; if ge, rate greater or equal ideal
  458. cmp [eax].PcPrcbData.PbMaximumDpcQueueDepth, 1 ; check if depth one
  459. je short Kutp55 ; if eq, maximum depth is one
  460. dec dword ptr [eax].PcPrcbData.PbMaximumDpcQueueDepth ; decrement depth
  461. jmp short Kutp55 ;
  462. ;
  463. ; The DPC queue is empty or a DPC routine is active or a DPC interrupt
  464. ; has been requested. Count down the adjustment threshold and if the
  465. ; count reaches zero, then increment the maximum DPC queue depth, but
  466. ; no above the initial value and reset the adjustment threshold value.
  467. ;
  468. Kutp53: dec dword ptr [eax].PcPrcbData.PbAdjustDpcThreshold ; decrement threshold
  469. jnz short Kutp55 ; if nz, threshold not zero
  470. mov ecx, _KiAdjustDpcThreshold ; reset initial threshold counter
  471. mov [eax].PcprcbData.PbAdjustDpcThreshold, ecx ;
  472. mov ecx, _KiMaximumDpcQueueDepth ; get maximum DPC queue depth
  473. cmp ecx, [eax].PcPrcbData.PbMaximumDpcQueueDepth ; check depth
  474. je short Kutp55 ; if eq, aleady a maximum level
  475. inc dword ptr [eax].PcPrcbData.PbMaximumDpcQueueDepth ; increment maximum depth
  476. ;
  477. ; Decrement current thread quantum and check to determine if a quantum end
  478. ; has occurred.
  479. ;
  480. ALIGN 4
  481. Kutp55: sub byte ptr [ebx]+ThQuantum, CLOCK_QUANTUM_DECREMENT ; decrement quantum
  482. jg Kutp75 ; if > 0, time remaining on quantum
  483. ;
  484. ; Set quantum end flag and initiate a dispather interrupt on the current
  485. ; processor.
  486. ;
  487. cmp ebx,[eax].PcPrcbData.PbIdleThread ; check if idle thread
  488. jz Kutp75 ; if z, then idle thread
  489. mov [eax].PcPrcbData.PbQuantumEnd, esp ; set quantum end indicator
  490. mov ecx, DISPATCH_LEVEL ; request dispatch interrupt
  491. fstCall HalRequestSoftwareInterrupt ;
  492. Kutp75: ;
  493. pop ebx ;
  494. stdRET _KeUpdateRunTime ;
  495. if DBG
  496. kutp_skiptick:
  497. mov byte ptr [eax]+PcPrcbData+PbSkipTick, 0
  498. stdRET _KeUpdateRunTime
  499. endif
  500. stdENDP _KeUpdateRunTime
  501. ;++
  502. ;
  503. ; PROFILING SUPPORT
  504. ;
  505. ;--
  506. ;++
  507. ;
  508. ; VOID
  509. ; KeProfileInterrupt (
  510. ; IN PKTRAP_FRAME TrapFrame,
  511. ; )
  512. ;
  513. ; Routine Description:
  514. ;
  515. ; This procedure is the ISR for the profile sampling interrupt,
  516. ; which for x86 machines is driven off the 8254 timer1 channel 0.
  517. ;
  518. ; The procedure scans the list of profile objects, looking for those
  519. ; which match the address space and return program counter captured
  520. ; at entry. For each object that does match, the counter in its
  521. ; profile buffer matching the bucket the PC falls into is computed,
  522. ; and that counter is incremented.
  523. ;
  524. ; N.B. This routine is executed on all processors in a multiprocess
  525. ; system.
  526. ;
  527. ; Arguments:
  528. ;
  529. ; Return Address (esp)
  530. ;
  531. ; TrapFrame (esp+4) - supplies pointer to profile trap frame
  532. ;
  533. ; Environment:
  534. ;
  535. ; IRQL = KiProfileIrql
  536. ;
  537. ;
  538. ; Return Value:
  539. ;
  540. ; None.
  541. ;
  542. ; WARNING: Uses ALL registers
  543. ;
  544. ;--
  545. cPublicProc _KeProfileInterrupt ,1
  546. ;
  547. ; rearrange arguments to pass a source of 0 to KeProfileInterruptWithSource
  548. ;
  549. pop eax ; return code in eax
  550. pop ebx ; trap frame in ebx
  551. push 0 ; push source of 0 (ProfileTime)
  552. push ebx ; push trap frame
  553. push eax ; push return address
  554. jmp short _KeProfileInterruptWithSource@8
  555. stdENDP _KeProfileInterrupt
  556. ;++
  557. ;
  558. ; VOID
  559. ; KeProfileInterruptWithSource (
  560. ; IN PKTRAP_FRAME TrapFrame,
  561. ; IN KPROFILE_SOURCE ProfileSource
  562. ; )
  563. ;
  564. ; Routine Description:
  565. ;
  566. ; This procedure is the ISR for the multiple-source profile interrupt.
  567. ;
  568. ; Since no x86 HAL currently implements any source other than the
  569. ; clock interrupt, this routine is just a stub that calls KeProfileInterrupt
  570. ;
  571. ; Arguments:
  572. ;
  573. ; Return Address (esp)
  574. ;
  575. ; TrapFrame (esp+4) - supplies pointer to profile trap frame
  576. ;
  577. ; ProfileSource (esp+8) - supplies source of profile interrupt
  578. ;
  579. ; Environment:
  580. ;
  581. ; IRQL = KiProfileIrql
  582. ;
  583. ;
  584. ; Return Value:
  585. ;
  586. ; None.
  587. ;
  588. ; WARNING: Uses ALL registers
  589. ;
  590. ;--
  591. cPublicProc _KeProfileInterruptWithSource,2
  592. kipieip equ <dword ptr [ebp+TsEip]>
  593. kipsegcs equ <word ptr [ebp+TsSegCs]>
  594. kipeflags equ <dword ptr [ebp+TsEFlags]>
  595. mov ebp, dword ptr [esp+4] ; (ebp)-> trap frame
  596. inc dword ptr PCR[PcPrcbData+PbInterruptCount]
  597. cmp _PPerfGlobalGroupMask, 0 ; check if event tracing is on
  598. je short kipi03
  599. ;; add profile interrupt to perfinfo
  600. mov ecx, [esp+8]
  601. mov edx,kipieip
  602. fstCall PerfProfileInterrupt
  603. mov ebp, dword ptr [esp+4] ; (ebp)-> trap frame
  604. kipi03:
  605. ifndef NT_UP
  606. lea eax,_KiProfileLock
  607. kipi05: ACQUIRE_SPINLOCK eax,kipi96
  608. endif
  609. ;
  610. ; Update profile data
  611. ;
  612. ; NOTE:
  613. ; System and Process update loops are duplicates, to avoid overhead
  614. ; of call instruction in what could be very high freq. interrupt.
  615. ; be sure to update both loops for changes.
  616. ;
  617. ; NOTE:
  618. ; The process loop contains code to update segment profile objects.
  619. ; This code is not present in the system loop, because we do not
  620. ; allow attachment of profile objects for non-flat segments on a
  621. ; system wide basis.
  622. ;
  623. ; NOTE:
  624. ; Profiling in V86 mode is handled by converting the CS:IP value to
  625. ; a linear address (CS<<4 + IP)
  626. ;
  627. inc ProfileCount ; total number of hits
  628. ;
  629. ; Update system profile entries
  630. ;
  631. mov ebx, kipieip
  632. mov edx,offset FLAT:_KiProfileListHead
  633. mov esi,[edx].LsFlink ; (esi) -> profile object
  634. ifndef NT_UP
  635. mov edi, PCR[PcSetMember] ; (edi) = current processor
  636. endif
  637. mov ecx, [esp+8] ; (cx) = profile source
  638. cmp esi,edx
  639. je kipi30 ; end of system list, go do process
  640. ;
  641. ; (ebx) = sample program counter
  642. ; (esi) -> profile object
  643. ;
  644. ALIGN 4
  645. kipi10: cmp ebx,[esi+PfRangeBase-PfProfileListEntry] ; >= base?
  646. jb kipi20 ; no, skip entry
  647. cmp ebx,[esi+PfRangeLimit-PfProfileListEntry] ; < limit?
  648. jae kipi20 ; no, skip entry
  649. cmp cx,word ptr [esi+PfSource-PfProfileListEntry] ; == source?
  650. jne kipi20 ; no, skip entry
  651. ifndef NT_UP
  652. test edi,[esi+PfAffinity-PfProfileListEntry] ; affinity match?
  653. jz kipi20 ; no, skip entry
  654. endif
  655. ;
  656. ; RangeBase <= program counter < RangeLimit, we have a hit
  657. ;
  658. sub ebx,[esi+PfRangeBase-PfProfileListEntry] ; (ebx) = offset in profile range
  659. mov cl,[esi+PfBucketShift-PfProfileListEntry]
  660. shr ebx,cl
  661. and ebx,NOT 3 ; (ebx) = offset of counter for bucket
  662. mov edi,[esi+PfBuffer-PfProfileListEntry] ; (edi) -> buffer
  663. inc dword ptr [edi+ebx] ; record hit
  664. mov ebx, kipieip ; (ebx) = sample pc
  665. mov ecx, [esp+8] ; (cx) = profile source
  666. ifndef NT_UP
  667. mov edi, PCR[PcSetMember] ; (edi) = current processor
  668. endif
  669. ;
  670. ; Go to next entry
  671. ;
  672. ALIGN 4
  673. kipi20: mov esi,[esi].LsFlink ; (esi) -> profile object
  674. cmp esi,edx
  675. jne kipi10 ; not end of list, repeat
  676. ;
  677. ; Update process profile entries
  678. ; (ebx) = sample program counter
  679. ;
  680. ALIGN 4
  681. kipi30: mov eax,PCR[PcPrcbData+PbCurrentThread] ; (eax)-> current thread
  682. mov eax,ThApcState+AsProcess[eax] ; (eax)-> current process
  683. lea edx,[eax]+PrProfileListHead ; (edx)-> listhead
  684. mov esi,[edx].LsFlink ; (esi)-> profile object
  685. cmp esi,edx
  686. je kipi60 ; process list end, return
  687. ;
  688. ; Check for 16 bitness
  689. ;
  690. movzx ecx,word ptr kipsegcs
  691. test kipeflags,EFLAGS_V86_MASK
  692. jnz kipi100 ; convert cs:ip to linear
  693. cmp cx,KGDT_R0_CODE
  694. je short kipi40
  695. cmp cx,KGDT_R3_CODE or RPL_MASK
  696. jne kipi110
  697. ;
  698. ; (ebx) = sample program counter
  699. ; (esi) -> profile object
  700. ;
  701. ALIGN 4
  702. kipi40: cmp [esi+PfSegment-PfProfileListEntry],word ptr 0 ; flat object?
  703. jne kipi50 ; no, skip entry
  704. cmp ebx,[esi+PfRangeBase-PfProfileListEntry] ; >= base?
  705. jb kipi50 ; no, skip entry
  706. cmp ebx,[esi+PfRangeLimit-PfProfileListEntry] ; < limit?
  707. jae kipi50 ; no, skip entry
  708. mov ecx, [esp+8] ; (cx) = profile source
  709. cmp cx,word ptr [esi+PfSource-PfProfileListEntry] ; == source?
  710. jne kipi50 ; no, skip entry
  711. ifndef NT_UP
  712. mov edi,PCR[PcSetMember] ; (edi) = set member
  713. test edi,[esi+PfAffinity-PfProfileListEntry] ; affinity match?
  714. jz kipi50 ; no, skip entry
  715. endif
  716. ;
  717. ; RangeBase <= program counter < RangeLimit, we have a hit
  718. ;
  719. sub ebx,[esi+PfRangeBase-PfProfileListEntry] ; (ebx) = offset in profile range
  720. mov cl,[esi+PfBucketShift-PfProfileListEntry]
  721. shr ebx,cl
  722. and ebx,NOT 3 ; (ebx) = offset of counter for bucket
  723. mov edi,[esi+PfBuffer-PfProfileListEntry] ; (edi) -> buffer
  724. inc dword ptr [edi+ebx] ; record hit
  725. mov ebx, kipieip ; (ebx) = sample pc
  726. mov ecx, [esp+8] ; (cx) = profile source
  727. ;
  728. ; Go to next entry
  729. ;
  730. ALIGN 4
  731. kipi50: mov esi,[esi].LsFlink ; (esi) -> profile object
  732. cmp esi,edx
  733. jne kipi40 ; not end of list, repeat
  734. ALIGN 4
  735. kipi60:
  736. ifndef NT_UP
  737. lea eax,_KiProfileLock
  738. RELEASE_SPINLOCK eax
  739. endif
  740. stdRet _KeProfileInterruptWithSource
  741. ifndef NT_UP
  742. ALIGN 4
  743. kipi96: SPIN_ON_SPINLOCK eax,kipi05,,DbgMp
  744. endif
  745. ALIGN 4
  746. kipi100:
  747. shl ecx,4 ; segment -> paragraph
  748. add ebx,ecx ; paragraph offset -> linear
  749. jmp kipi40
  750. ;
  751. ; Update segment profile objects
  752. ;
  753. ;
  754. ; (ebx) = sample program counter
  755. ; (esi) -> profile object
  756. ;
  757. ALIGN 4
  758. kipi110:
  759. cmp [esi+PfSegment-PfProfileListEntry],ecx ; This segment?
  760. jne kipi120 ; no, skip entry
  761. cmp ebx,[esi+PfRangeBase-PfProfileListEntry] ; >= base?
  762. jb kipi120 ; no, skip entry
  763. cmp ebx,[esi+PfRangeLimit-PfProfileListEntry] ; < limit?
  764. jae kipi120 ; no, skip entry
  765. mov ecx, [esp+8] ; (cx) = profile source
  766. cmp cx,word ptr [esi+PfSource-PfProfileListEntry] ; == source?
  767. jne kipi120 ; no, skip entry
  768. ifndef NT_UP
  769. mov edi,PCR[PcSetMember] ; (edi) = set member
  770. test edi,[esi+PfAffinity-PfProfileListEntry] ; affinity match?
  771. jnz kipi120 ; no, skip entry
  772. endif
  773. ;
  774. ; RangeBase <= program counter < RangeLimit, we have a hit
  775. ;
  776. sub ebx,[esi+PfRangeBase-PfProfileListEntry] ; (ebx) = offset in profile range
  777. mov cl,[esi+PfBucketShift-PfProfileListEntry]
  778. shr ebx,cl
  779. and ebx,NOT 3 ; (ebx) = offset of counter for bucket
  780. mov edi,[esi+PfBuffer-PfProfileListEntry] ; (edi) -> buffer
  781. inc dword ptr [edi+ebx] ; record hit
  782. mov ebx, kipieip ; (ebx) = sample pc
  783. mov cx,kipsegcs ; ecx = sample cs
  784. ;
  785. ; Go to next entry
  786. ;
  787. ALIGN 4
  788. kipi120:
  789. mov esi,[esi].LsFlink ; (esi) -> profile object
  790. cmp esi,edx
  791. jne kipi110 ; not end of list, repeat
  792. jmp kipi60
  793. stdENDP _KeProfileInterruptWithSource
  794. _TEXT$00 ends
  795. end