Leaked source code of windows server 2003
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.

879 lines
28 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 declared 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 _KiProfileListHead:DWORD
  64. extrn _KiProfileLock:DWORD
  65. extrn _KiProfileInterval:DWORD
  66. extrn _KdDebuggerEnabled:BYTE
  67. EXTRNP _DbgBreakPoint
  68. EXTRNP _DbgBreakPointWithStatus,1
  69. EXTRNP _KdPollBreakIn
  70. EXTRNP _KiDeliverApc,3
  71. extrn _KeI386MachineType:DWORD
  72. extrn _PPerfGlobalGroupMask:DWORD
  73. EXTRNP PerfProfileInterrupt,2,,FASTCALL
  74. if DBG
  75. extrn _DbgPrint:near
  76. extrn _KiDPCTimeout:DWORD
  77. extrn _MsgDpcTimeout:BYTE
  78. endif
  79. ifdef NT_UP
  80. LOCK_INC equ inc
  81. else
  82. LOCK_INC equ lock inc
  83. endif
  84. _DATA SEGMENT DWORD PUBLIC 'DATA'
  85. public ProfileCount
  86. ProfileCount DD 0
  87. _DATA ends
  88. page ,132
  89. subttl "Update System Time"
  90. _TEXT$00 SEGMENT DWORD PUBLIC 'CODE'
  91. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  92. ;++
  93. ;
  94. ; VOID
  95. ; KeUpdateSystemTime (
  96. ; IN KIRQL PreviousIrql,
  97. ; IN KTRAP_FRAME TrapFrame
  98. ; )
  99. ;
  100. ; Routine Description:
  101. ;
  102. ; This routine is entered as the result of an interrupt generated by CLOCK2.
  103. ; Its function is to update the system time and check to determine if a timer
  104. ; has expired.
  105. ;
  106. ; N.B. This routine is executed on a single processor in a multiprocessor
  107. ; system. The remainder of the processors only execute the quantum end
  108. ; and runtime update code.
  109. ;
  110. ; N.B. This routine is not called, but directly jumped to. Thus, there
  111. ; is no return address. It returns via the INTERRUPT_EXIT macro.
  112. ;
  113. ; Arguments:
  114. ;
  115. ; PreviousIrql (esp) - supplies previous irql of system
  116. ;
  117. ; HardwareVector (esp+4) - supplies hardware vector for EndSystemInterrupt
  118. ;
  119. ; TrapFrame (esp+8) - supplies base of trap frame
  120. ;
  121. ; EAX is the TimeIncrement value
  122. ;
  123. ; EBP is a pointer to the trap frame
  124. ;
  125. ;
  126. ; Environment:
  127. ;
  128. ; IRQL = CLOCK_LEVEL
  129. ;
  130. ; Return Value:
  131. ;
  132. ; None.
  133. ;
  134. ;--
  135. cPublicProc _KeUpdateSystemTime ,0
  136. .FPO (2, 0, 0, 0, 0, 1) ; treat params as locals since functions is JMPed too
  137. if DBG
  138. cmp byte ptr PCR[PcPrcbData+PbSkipTick], 0
  139. jnz kust_skiptick
  140. endif
  141. ;
  142. ; Update interrupt time.
  143. ;
  144. ; N.B. The interrupt time is updated in a very strict manner so that an
  145. ; interlock does not have to be used in an MP system to read time.
  146. ;
  147. mov ecx,USER_SHARED_DATA ; get address of user shared data
  148. mov edi,[ecx].UsInterruptTime+0 ; get low interrupt time
  149. mov esi,[ecx].UsInterruptTime+4 ; get high interrupt time
  150. add edi,eax ; add time increment
  151. adc esi,0 ; propagate carry
  152. mov [ecx].UsInterruptTime+8,esi ; store high 2 interrupt time
  153. mov [ecx].UsInterruptTime+0,edi ; store low interrupt time
  154. mov [ecx].UsInterruptTime+4,esi ; store high 1 interrupt time
  155. sub _KiTickOffset,eax ; subtract time increment
  156. mov eax,_KeTickCount+0 ; get low tick count
  157. mov ebx,eax ; copy low tick count
  158. jg kust10 ; if greater, not complete tick
  159. ;
  160. ; Update system time.
  161. ;
  162. ; N.B. The system time is updated in a very strict manner so that an
  163. ; interlock does not have to be used in an MP system to read time.
  164. ;
  165. mov ebx,USER_SHARED_DATA ; get address of user shared data
  166. mov ecx,[ebx].UsSystemTime+0 ; get low system time
  167. mov edx,[ebx].UsSystemTime+4 ; get high system time
  168. add ecx,_KeTimeAdjustment ; add time increment
  169. adc edx,0 ; propagate carry
  170. mov [ebx].UsSystemTime+8,edx ; store high 2 system time
  171. mov [ebx].UsSystemTime+0,ecx ; store low system time
  172. mov [ebx].UsSystemTime+4,edx ; store high 1 system time
  173. mov ebx,eax ; restore low tick count
  174. ;
  175. ; Update tick count.
  176. ;
  177. ; N.B. The tick count is updated in a very strict manner so that an
  178. ; interlock does not have to be used in an MP system to read count.
  179. ;
  180. mov ecx,eax ; copy low tick count
  181. mov edx,_KeTickCount+4 ; get high tick count
  182. add ecx,1 ; increment tick count
  183. adc edx,0 ; propagate carry
  184. mov _KeTickCount+8,edx ; store high 2 tick count
  185. mov _KeTickCount+0,ecx ; store low tick count
  186. mov _KeTickCount+4,edx ; store high 1 tick count
  187. mov USERDATA[UsTickCount]+8, edx ; store USD high 2 tick count
  188. mov USERDATA[UsTickCount]+0, ecx ; store USD low tick count
  189. mov USERDATA[UsTickCount]+4, edx ; store USD high 1 tick count
  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. cmp dword ptr [ecx]+PbTimerRequest, 0 ; check if expiration active
  246. jne short kustxx ; if ne, expiration already active
  247. mov [ecx]+PbTimerRequest, esp ; set timer request
  248. mov [ecx]+PbTimerHand, ebx ; set timer hand value
  249. mov ecx, DISPATCH_LEVEL ; request dispatch interrupt
  250. fstCall HalRequestSoftwareInterrupt ;
  251. ;
  252. ; If the debugger is enabled, check if a break is requested.
  253. ;
  254. kustxx: cmp _KdDebuggerEnabled, 0 ; check if a debugger is enabled
  255. jnz short kust45 ;if nz, debugger is enabled
  256. kust30: cmp _KiTickOffset,0 ; check if full tick
  257. jg short Kust40 ; if not less, not a full tick
  258. mov eax,_KeMaximumIncrement ; get maximum time incrmeent
  259. add _KiTickOffset,eax ; add maximum tine to residue
  260. ;
  261. ; call KeUpdateRunTime to do the actual work
  262. ;
  263. ; TOS const PreviousIrql
  264. push [esp]
  265. call _KeUpdateRunTime@4
  266. ;
  267. ; Do interrupt exit processing
  268. ;
  269. INTERRUPT_EXIT
  270. kust40:
  271. inc dword ptr PCR[PcPrcbData+PbInterruptCount]
  272. INTERRUPT_EXIT
  273. kust45: stdCall _KdPollBreakIn
  274. or al,al
  275. jz short kust30
  276. stdCall _DbgBreakPointWithStatus,<DBG_STATUS_CONTROL_C>
  277. jmp short kust30
  278. if DBG
  279. kust_skiptick:
  280. mov byte ptr PCR[PcPrcbData+PbSkipTick], 0
  281. jmp short kust40
  282. endif
  283. stdENDP _KeUpdateSystemTime
  284. page ,132
  285. subttl "Update Thread and Process Runtime"
  286. ;++
  287. ;
  288. ; Routine Description:
  289. ;
  290. ; This routines does the actual work to update the runtime of the current
  291. ; thread, update the runtime of the current thread's process, and
  292. ; decrement the current thread's quantum.
  293. ;
  294. ; It also updates the system global counters for user and kernel mode time.
  295. ;
  296. ; It increments InterruptCount so that clock ticks get counted as
  297. ; interrupts.
  298. ;
  299. ; Arguments:
  300. ;
  301. ; esp+4 constant PreviousIrql
  302. ;
  303. ; ebp MUST point to the machine state frame.
  304. ;
  305. ; Return Value:
  306. ;
  307. ; None.
  308. ;
  309. ;--
  310. cPublicProc _KeUpdateRunTime ,1
  311. cPublicFpo 1, 1
  312. mov eax, PCR[PcSelfPcr]
  313. if DBG
  314. cmp byte ptr [eax]+PcPrcbData+PbSkipTick, 0
  315. jnz kutp_skiptick
  316. endif
  317. push ebx ; we will destroy ebx
  318. inc dword ptr [eax]+PcPrcbData+PbInterruptCount
  319. mov ebx, [eax]+PcPrcbData+PbCurrentThread ; (ebx)->current thread
  320. mov ecx, ThApcState+AsProcess[ebx]
  321. ; (ecx)->current thread's process
  322. test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
  323. jne Kutp20 ; if ne, user mode
  324. test byte ptr [ebp]+TsSegCs, MODE_MASK ; test if prev mode was kernel
  325. jne Kutp20 ; if ne, user mode
  326. ;
  327. ; Update the total time spent in kernel mode
  328. ;
  329. inc dword ptr [eax].PcPrcbData.PbKernelTime
  330. cmp byte ptr [esp+8], DISPATCH_LEVEL
  331. jc short Kutp4 ; OldIrql<2, then kernel
  332. ja short Kutp3 ; OldIrql>2, then interrupt
  333. cmp byte ptr PCR[PcPrcbData.PbDpcRoutineActive], 0
  334. jz short Kutp4 ; Executing Dpc?, no then thread time
  335. inc dword ptr [eax].PcPrcbData.PbDpcTime
  336. if DBG
  337. ;
  338. ; Check for dpcs which run for too long
  339. ;
  340. inc dword ptr [eax].PcPrcbData.PbDebugDpcTime
  341. mov edx, _KiDPCTimeout
  342. cmp dword ptr [eax].PcPrcbData.PbDebugDpcTime, edx
  343. jc Kutp50 ; Jump if not over limit
  344. ;
  345. ; Dpc time has exceeded the allowed quanta
  346. ;
  347. push offset FLAT:_MsgDpcTimeout ; push message address
  348. call _DbgPrint ; print debug message
  349. add esp, 1 * 4 ; remove arguments from stack
  350. cmp _KdDebuggerEnabled, 0 ; check if debugger enabled
  351. je short Kutp6 ; if eq, no debugger, continue
  352. stdCall _DbgBreakPoint ; break into debugger
  353. Kutp6: mov eax, PCR[PcSelfPcr] ; restore PCR address
  354. mov dword ptr [eax].PcPrcbData.PbDebugDpcTime, 0 ; Reset Time
  355. endif
  356. jmp Kutp50
  357. ALIGN 4
  358. Kutp3:
  359. ;
  360. ; Update the time spent at interrupt time for this processor
  361. ;
  362. inc dword ptr [eax].PcPrcbData.PbInterruptTime
  363. jmp Kutp50
  364. ALIGN 4
  365. Kutp4:
  366. ;
  367. ; Update the time spent in kernel mode for the current thread and the current
  368. ; thread's process.
  369. ;
  370. inc dword ptr [ebx]+ThKernelTime
  371. LOCK_INC dword ptr [ecx]+PrKernelTime
  372. jmp Kutp50
  373. ;
  374. ; Update total time spent in user mode
  375. ;
  376. ALIGN 4
  377. Kutp20:
  378. inc dword ptr [eax].PcPrcbData.PbUserTime
  379. ;
  380. ; Update the time spend in user mode for the current thread and the current
  381. ; thread's process.
  382. ;
  383. inc dword ptr [ebx]+ThUserTime
  384. LOCK_INC dword ptr [ecx]+PrUserTime
  385. ;
  386. ; Update the DPC request rate which is computed as the average between
  387. ; the previous rate and the current rate.
  388. ;
  389. ALIGN 4
  390. Kutp50: mov ecx, [eax].PcPrcbData.PbDpcCount ; get current DPC count
  391. mov edx, [eax].PcPrcbData.PbDpcLastCount ; get last DPC count
  392. mov [eax].PcPrcbData.PbDpcLastCount, ecx ; set last DPC count
  393. sub ecx, edx ; compute count during interval
  394. add ecx, [eax].PcPrcbData.PbDpcRequestRate ; compute sum
  395. shr ecx, 1 ; average current and last
  396. mov [eax].PcPrcbData.PbDpcRequestRate, ecx ; set new DPC request rate
  397. ;
  398. ; If the current DPC queue depth is not zero, a DPC routine is not active,
  399. ; and a DPC interrupt has not been requested, then request a dispatch
  400. ; interrupt, decrement the maximum DPC queue depth, and reset the threshold
  401. ; counter if appropriate.
  402. ;
  403. cmp dword ptr [eax].PcPrcbData.PbDpcQueueDepth, 0 ; check queue depth
  404. je short Kutp53 ; if eq, DPC queue depth is zero
  405. cmp byte ptr [eax].PcPrcbData.PbDpcRoutineActive, 0 ; check if DPC active
  406. jne short Kutp53 ; if ne, DPC routine active
  407. cmp byte ptr [eax].PcPrcbData.PbDpcInterruptRequested, 0 ; check if interrupt
  408. jne short Kutp53 ; if ne, DPC routine active
  409. mov ecx, DISPATCH_LEVEL ; request a dispatch interrupt
  410. fstCall HalRequestSoftwareInterrupt ;
  411. mov eax, PCR[PcSelfPcr] ; restore address of current PCR
  412. mov ecx, [eax].PcPrcbData.PbDpcRequestRate ; get DPC request rate
  413. mov edx, _KiAdjustDpcThreshold ; reset initial threshold counter
  414. mov [eax].PcPrcbData.PbAdjustDpcThreshold, edx ;
  415. cmp ecx, _KiIdealDpcRate ; test if current rate less than ideal
  416. jge short Kutp55 ; if ge, rate greater or equal ideal
  417. cmp [eax].PcPrcbData.PbMaximumDpcQueueDepth, 1 ; check if depth one
  418. je short Kutp55 ; if eq, maximum depth is one
  419. dec dword ptr [eax].PcPrcbData.PbMaximumDpcQueueDepth ; decrement depth
  420. jmp short Kutp55 ;
  421. ;
  422. ; The DPC queue is empty or a DPC routine is active or a DPC interrupt
  423. ; has been requested. Count down the adjustment threshold and if the
  424. ; count reaches zero, then increment the maximum DPC queue depth, but
  425. ; no above the initial value and reset the adjustment threshold value.
  426. ;
  427. Kutp53: dec dword ptr [eax].PcPrcbData.PbAdjustDpcThreshold ; decrement threshold
  428. jnz short Kutp55 ; if nz, threshold not zero
  429. mov ecx, _KiAdjustDpcThreshold ; reset initial threshold counter
  430. mov [eax].PcprcbData.PbAdjustDpcThreshold, ecx ;
  431. mov ecx, _KiMaximumDpcQueueDepth ; get maximum DPC queue depth
  432. cmp ecx, [eax].PcPrcbData.PbMaximumDpcQueueDepth ; check depth
  433. je short Kutp55 ; if eq, aleady a maximum level
  434. inc dword ptr [eax].PcPrcbData.PbMaximumDpcQueueDepth ; increment maximum depth
  435. ;
  436. ; Decrement current thread quantum and check to determine if a quantum end
  437. ; has occurred.
  438. ;
  439. ALIGN 4
  440. Kutp55: sub byte ptr [ebx]+ThQuantum, CLOCK_QUANTUM_DECREMENT ; decrement quantum
  441. jg Kutp75 ; if > 0, time remaining on quantum
  442. ;
  443. ; Set quantum end flag and initiate a dispather interrupt on the current
  444. ; processor.
  445. ;
  446. cmp ebx,[eax].PcPrcbData.PbIdleThread ; check if idle thread
  447. jz Kutp75 ; if z, then idle thread
  448. mov byte ptr [eax].PcPrcbData.PbQuantumEnd, 1 ; set quantum end indicator
  449. mov ecx, DISPATCH_LEVEL ; request dispatch interrupt
  450. fstCall HalRequestSoftwareInterrupt ;
  451. Kutp75: ;
  452. pop ebx ;
  453. stdRET _KeUpdateRunTime ;
  454. if DBG
  455. kutp_skiptick:
  456. mov byte ptr [eax]+PcPrcbData+PbSkipTick, 0
  457. stdRET _KeUpdateRunTime
  458. endif
  459. stdENDP _KeUpdateRunTime
  460. ;++
  461. ;
  462. ; PROFILING SUPPORT
  463. ;
  464. ;--
  465. ;++
  466. ;
  467. ; VOID
  468. ; KeProfileInterrupt (
  469. ; IN PKTRAP_FRAME TrapFrame,
  470. ; )
  471. ;
  472. ; Routine Description:
  473. ;
  474. ; This procedure is the ISR for the profile sampling interrupt,
  475. ; which for x86 machines is driven off the 8254 timer1 channel 0.
  476. ;
  477. ; The procedure scans the list of profile objects, looking for those
  478. ; which match the address space and return program counter captured
  479. ; at entry. For each object that does match, the counter in its
  480. ; profile buffer matching the bucket the PC falls into is computed,
  481. ; and that counter is incremented.
  482. ;
  483. ; N.B. This routine is executed on all processors in a multiprocess
  484. ; system.
  485. ;
  486. ; Arguments:
  487. ;
  488. ; Return Address (esp)
  489. ;
  490. ; TrapFrame (esp+4) - supplies pointer to profile trap frame
  491. ;
  492. ; Environment:
  493. ;
  494. ; IRQL = KiProfileIrql
  495. ;
  496. ;
  497. ; Return Value:
  498. ;
  499. ; None.
  500. ;
  501. ; WARNING: Uses ALL registers
  502. ;
  503. ;--
  504. cPublicProc _KeProfileInterrupt ,1
  505. ;
  506. ; rearrange arguments to pass a source of 0 to KeProfileInterruptWithSource
  507. ;
  508. pop eax ; return code in eax
  509. pop ebx ; trap frame in ebx
  510. push 0 ; push source of 0 (ProfileTime)
  511. push ebx ; push trap frame
  512. push eax ; push return address
  513. jmp short _KeProfileInterruptWithSource@8
  514. stdENDP _KeProfileInterrupt
  515. ;++
  516. ;
  517. ; VOID
  518. ; KeProfileInterruptWithSource (
  519. ; IN PKTRAP_FRAME TrapFrame,
  520. ; IN KPROFILE_SOURCE ProfileSource
  521. ; )
  522. ;
  523. ; Routine Description:
  524. ;
  525. ; This procedure is the ISR for the multiple-source profile interrupt.
  526. ;
  527. ; Since no x86 HAL currently implements any source other than the
  528. ; clock interrupt, this routine is just a stub that calls KeProfileInterrupt
  529. ;
  530. ; Arguments:
  531. ;
  532. ; Return Address (esp)
  533. ;
  534. ; TrapFrame (esp+4) - supplies pointer to profile trap frame
  535. ;
  536. ; ProfileSource (esp+8) - supplies source of profile interrupt
  537. ;
  538. ; Environment:
  539. ;
  540. ; IRQL = KiProfileIrql
  541. ;
  542. ;
  543. ; Return Value:
  544. ;
  545. ; None.
  546. ;
  547. ; WARNING: Uses ALL registers
  548. ;
  549. ;--
  550. cPublicProc _KeProfileInterruptWithSource,2
  551. kipieip equ <dword ptr [ebp+TsEip]>
  552. kipsegcs equ <word ptr [ebp+TsSegCs]>
  553. kipeflags equ <dword ptr [ebp+TsEFlags]>
  554. mov ebp, dword ptr [esp+4] ; (ebp)-> trap frame
  555. inc dword ptr PCR[PcPrcbData+PbInterruptCount]
  556. cmp _PPerfGlobalGroupMask, 0 ; check if event tracing is on
  557. je short kipi03
  558. ;; add profile interrupt to perfinfo
  559. mov ecx, [esp+8]
  560. mov edx,kipieip
  561. fstCall PerfProfileInterrupt
  562. mov ebp, dword ptr [esp+4] ; (ebp)-> trap frame
  563. kipi03:
  564. ifndef NT_UP
  565. lea eax,_KiProfileLock
  566. kipi05: ACQUIRE_SPINLOCK eax,kipi96
  567. endif
  568. ;
  569. ; Update profile data
  570. ;
  571. ; NOTE:
  572. ; System and Process update loops are duplicates, to avoid overhead
  573. ; of call instruction in what could be very high freq. interrupt.
  574. ; be sure to update both loops for changes.
  575. ;
  576. ; NOTE:
  577. ; The process loop contains code to update segment profile objects.
  578. ; This code is not present in the system loop, because we do not
  579. ; allow attachment of profile objects for non-flat segments on a
  580. ; system wide basis.
  581. ;
  582. ; NOTE:
  583. ; Profiling in V86 mode is handled by converting the CS:IP value to
  584. ; a linear address (CS<<4 + IP)
  585. ;
  586. inc ProfileCount ; total number of hits
  587. ;
  588. ; Update system profile entries
  589. ;
  590. mov ebx, kipieip
  591. mov edx,offset FLAT:_KiProfileListHead
  592. mov esi,[edx].LsFlink ; (esi) -> profile object
  593. ifndef NT_UP
  594. mov edi, PCR[PcSetMember] ; (edi) = current processor
  595. endif
  596. mov ecx, [esp+8] ; (cx) = profile source
  597. cmp esi,edx
  598. je kipi30 ; end of system list, go do process
  599. ;
  600. ; (ebx) = sample program counter
  601. ; (esi) -> profile object
  602. ;
  603. ALIGN 4
  604. kipi10: cmp ebx,[esi+PfRangeBase-PfProfileListEntry] ; >= base?
  605. jb kipi20 ; no, skip entry
  606. cmp ebx,[esi+PfRangeLimit-PfProfileListEntry] ; < limit?
  607. jae kipi20 ; no, skip entry
  608. cmp cx,word ptr [esi+PfSource-PfProfileListEntry] ; == source?
  609. jne kipi20 ; no, skip entry
  610. ifndef NT_UP
  611. test edi,[esi+PfAffinity-PfProfileListEntry] ; affinity match?
  612. jz kipi20 ; no, skip entry
  613. endif
  614. ;
  615. ; RangeBase <= program counter < RangeLimit, we have a hit
  616. ;
  617. sub ebx,[esi+PfRangeBase-PfProfileListEntry] ; (ebx) = offset in profile range
  618. mov cl,[esi+PfBucketShift-PfProfileListEntry]
  619. shr ebx,cl
  620. and ebx,NOT 3 ; (ebx) = offset of counter for bucket
  621. mov edi,[esi+PfBuffer-PfProfileListEntry] ; (edi) -> buffer
  622. inc dword ptr [edi+ebx] ; record hit
  623. mov ebx, kipieip ; (ebx) = sample pc
  624. mov ecx, [esp+8] ; (cx) = profile source
  625. ifndef NT_UP
  626. mov edi, PCR[PcSetMember] ; (edi) = current processor
  627. endif
  628. ;
  629. ; Go to next entry
  630. ;
  631. ALIGN 4
  632. kipi20: mov esi,[esi].LsFlink ; (esi) -> profile object
  633. cmp esi,edx
  634. jne kipi10 ; not end of list, repeat
  635. ;
  636. ; Update process profile entries
  637. ; (ebx) = sample program counter
  638. ;
  639. ALIGN 4
  640. kipi30: mov eax,PCR[PcPrcbData+PbCurrentThread] ; (eax)-> current thread
  641. mov eax,ThApcState+AsProcess[eax] ; (eax)-> current process
  642. lea edx,[eax]+PrProfileListHead ; (edx)-> listhead
  643. mov esi,[edx].LsFlink ; (esi)-> profile object
  644. cmp esi,edx
  645. je kipi60 ; process list end, return
  646. ;
  647. ; Check for 16 bitness
  648. ;
  649. movzx ecx,word ptr kipsegcs
  650. test kipeflags,EFLAGS_V86_MASK
  651. jnz kipi100 ; convert cs:ip to linear
  652. cmp cx,KGDT_R0_CODE
  653. je short kipi40
  654. cmp cx,KGDT_R3_CODE or RPL_MASK
  655. jne kipi110
  656. ;
  657. ; (ebx) = sample program counter
  658. ; (esi) -> profile object
  659. ;
  660. ALIGN 4
  661. kipi40: cmp [esi+PfSegment-PfProfileListEntry],word ptr 0 ; flat object?
  662. jne kipi50 ; no, skip entry
  663. cmp ebx,[esi+PfRangeBase-PfProfileListEntry] ; >= base?
  664. jb kipi50 ; no, skip entry
  665. cmp ebx,[esi+PfRangeLimit-PfProfileListEntry] ; < limit?
  666. jae kipi50 ; no, skip entry
  667. mov ecx, [esp+8] ; (cx) = profile source
  668. cmp cx,word ptr [esi+PfSource-PfProfileListEntry] ; == source?
  669. jne kipi50 ; no, skip entry
  670. ifndef NT_UP
  671. mov edi,PCR[PcSetMember] ; (edi) = set member
  672. test edi,[esi+PfAffinity-PfProfileListEntry] ; affinity match?
  673. jz kipi50 ; no, skip entry
  674. endif
  675. ;
  676. ; RangeBase <= program counter < RangeLimit, we have a hit
  677. ;
  678. sub ebx,[esi+PfRangeBase-PfProfileListEntry] ; (ebx) = offset in profile range
  679. mov cl,[esi+PfBucketShift-PfProfileListEntry]
  680. shr ebx,cl
  681. and ebx,NOT 3 ; (ebx) = offset of counter for bucket
  682. mov edi,[esi+PfBuffer-PfProfileListEntry] ; (edi) -> buffer
  683. inc dword ptr [edi+ebx] ; record hit
  684. mov ebx, kipieip ; (ebx) = sample pc
  685. mov ecx, [esp+8] ; (cx) = profile source
  686. ;
  687. ; Go to next entry
  688. ;
  689. ALIGN 4
  690. kipi50: mov esi,[esi].LsFlink ; (esi) -> profile object
  691. cmp esi,edx
  692. jne kipi40 ; not end of list, repeat
  693. ALIGN 4
  694. kipi60:
  695. ifndef NT_UP
  696. lea eax,_KiProfileLock
  697. RELEASE_SPINLOCK eax
  698. endif
  699. stdRet _KeProfileInterruptWithSource
  700. ifndef NT_UP
  701. ALIGN 4
  702. kipi96: SPIN_ON_SPINLOCK eax,kipi05,,DbgMp
  703. endif
  704. ALIGN 4
  705. kipi100:
  706. shl ecx,4 ; segment -> paragraph
  707. add ebx,ecx ; paragraph offset -> linear
  708. jmp kipi40
  709. ;
  710. ; Update segment profile objects
  711. ;
  712. ;
  713. ; (ebx) = sample program counter
  714. ; (esi) -> profile object
  715. ;
  716. ALIGN 4
  717. kipi110:
  718. cmp [esi+PfSegment-PfProfileListEntry],ecx ; This segment?
  719. jne kipi120 ; no, skip entry
  720. cmp ebx,[esi+PfRangeBase-PfProfileListEntry] ; >= base?
  721. jb kipi120 ; no, skip entry
  722. cmp ebx,[esi+PfRangeLimit-PfProfileListEntry] ; < limit?
  723. jae kipi120 ; no, skip entry
  724. mov ecx, [esp+8] ; (cx) = profile source
  725. cmp cx,word ptr [esi+PfSource-PfProfileListEntry] ; == source?
  726. jne kipi120 ; no, skip entry
  727. ifndef NT_UP
  728. mov edi,PCR[PcSetMember] ; (edi) = set member
  729. test edi,[esi+PfAffinity-PfProfileListEntry] ; affinity match?
  730. jnz kipi120 ; no, skip entry
  731. endif
  732. ;
  733. ; RangeBase <= program counter < RangeLimit, we have a hit
  734. ;
  735. sub ebx,[esi+PfRangeBase-PfProfileListEntry] ; (ebx) = offset in profile range
  736. mov cl,[esi+PfBucketShift-PfProfileListEntry]
  737. shr ebx,cl
  738. and ebx,NOT 3 ; (ebx) = offset of counter for bucket
  739. mov edi,[esi+PfBuffer-PfProfileListEntry] ; (edi) -> buffer
  740. inc dword ptr [edi+ebx] ; record hit
  741. mov ebx, kipieip ; (ebx) = sample pc
  742. mov cx,kipsegcs ; ecx = sample cs
  743. ;
  744. ; Go to next entry
  745. ;
  746. ALIGN 4
  747. kipi120:
  748. mov esi,[esi].LsFlink ; (esi) -> profile object
  749. cmp esi,edx
  750. jne kipi110 ; not end of list, repeat
  751. jmp kipi60
  752. stdENDP _KeProfileInterruptWithSource
  753. _TEXT$00 ends
  754. end