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.

457 lines
13 KiB

  1. title "Interval Clock Interrupt"
  2. ;++
  3. ;
  4. ; Copyright (c) 1989 Microsoft Corporation
  5. ;
  6. ; Module Name:
  7. ;
  8. ; spprofil.asm
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module implements the code necessary to initialize,
  13. ; field and process the profile 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.
  41. ;
  42. ; John Vert (jvert) 11-Jul-1991
  43. ; Moved from ke\i386 to hal\i386. Removed non-HAL stuff
  44. ;
  45. ; shie-lin tzong (shielint) 13-March-92
  46. ; Move System clock back to irq0 and use RTC (irq8) to generate
  47. ; profile interrupt. Performance counter and system clock use time1
  48. ; counter 0 of 8254.
  49. ;
  50. ;--
  51. .386p
  52. .xlist
  53. include hal386.inc
  54. include callconv.inc ; calling convention macros
  55. include i386\kimacro.inc
  56. include mac386.inc
  57. include i386\ix8259.inc
  58. include i386\ixcmos.inc
  59. .list
  60. EXTRNP _DbgBreakPoint,0,IMPORT
  61. EXTRNP _KeProfileInterrupt,1,IMPORT
  62. EXTRNP Kei386EoiHelper,0,IMPORT
  63. EXTRNP _HalEndSystemInterrupt,2
  64. EXTRNP _HalBeginSystemInterrupt,3
  65. EXTRNP _HalpAcquireCmosSpinLock ,0
  66. EXTRNP _HalpReleaseCmosSpinLock ,0
  67. ;
  68. ; Constants used to initialize CMOS/Real Time Clock
  69. ;
  70. D_INT032 EQU 8E00h ; access word for 386 ring 0 interrupt gate
  71. REGISTER_B_ENABLE_PERIODIC_INTERRUPT EQU 01000010B
  72. ; RT/CMOS Register 'B' Init byte
  73. ; Values for byte shown are
  74. ; Bit 7 = Update inhibit
  75. ; Bit 6 = Periodic interrupt enable
  76. ; Bit 5 = Alarm interrupt disable
  77. ; Bit 4 = Update interrupt disable
  78. ; Bit 3 = Square wave disable
  79. ; Bit 2 = BCD data format
  80. ; Bit 1 = 24 hour time mode
  81. ; Bit 0 = Daylight Savings disable
  82. REGISTER_B_DISABLE_PERIODIC_INTERRUPT EQU 00000010B
  83. _TEXT SEGMENT DWORD PUBLIC 'DATA'
  84. align 4
  85. ProfileIntervalTable dd 1221 ; unit = 100 ns
  86. dd 2441
  87. dd 4883
  88. dd 9766
  89. dd 19531
  90. dd 39063
  91. dd 78125
  92. dd 156250
  93. dd 312500
  94. dd 625000
  95. dd 1250000
  96. dd 2500000
  97. dd 5000000
  98. dd 5000000 OR 80000000H
  99. ProfileIntervalInitTable db 00100011B
  100. db 00100100B
  101. db 00100101B
  102. db 00100110B
  103. db 00100111B
  104. db 00101000B
  105. db 00101001B
  106. db 00101010B
  107. db 00101011B
  108. db 00101100B
  109. db 00101101B
  110. db 00101110B
  111. db 00101111B
  112. db 00101111B
  113. ;
  114. ; HALs wishing to reuse the code in this module should set the HAL
  115. ; global variable IxProfileVector to their profile vector.
  116. ;
  117. public _IxProfileVector
  118. _IxProfileVector dd PROFILE_VECTOR
  119. _TEXT ends
  120. _DATA SEGMENT DWORD PUBLIC 'DATA'
  121. RegisterAProfileValue db 00101000B ; default interval = 3.90625 ms
  122. ;
  123. ; The following array stores the per microsecond loop count for each
  124. ; central processor.
  125. ;
  126. HalpProfileInterval dd -1
  127. HalpProfilingStopped dd 1
  128. _DATA ends
  129. _TEXT SEGMENT DWORD PUBLIC 'CODE'
  130. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  131. ;++
  132. ;
  133. ; HalStartProfileInterrupt(
  134. ; IN ULONG Reserved
  135. ; );
  136. ;
  137. ; Routine Description:
  138. ;
  139. ; What we do here is change the interrupt
  140. ; rate from the slowest thing we can get away with to the value
  141. ; that's been KeSetProfileInterval
  142. ;
  143. ; All processors will run this routine, but it doesn't hurt to have
  144. ; each one reinitialize the CMOS, since none of them will be let go
  145. ; from the stall until they all finish.
  146. ;
  147. ;--
  148. cPublicProc _HalStartProfileInterrupt ,1
  149. ;
  150. ; On the SystemPro there is only one profile device, so starting/stopping
  151. ; is only done from one processor.
  152. ;
  153. ; Note: This code uses PbNumber so it doesn't touch any SystemPro specific
  154. ; PCR value (so the code can be re-used by other hals)
  155. ;
  156. mov eax, PCR[PcPrcb]
  157. cmp byte ptr [eax].PbNumber, 0
  158. jne epi_exit
  159. ; Mark profiling as active
  160. ;
  161. mov HalpProfilingStopped, 0
  162. ;
  163. ; Set the interrupt rate to what is actually needed
  164. ;
  165. stdCall _HalpAcquireCmosSpinLock ; intr disabled
  166. mov al, RegisterAProfileValue
  167. shl ax, 8
  168. mov al, 0AH ; Register A
  169. CMOS_WRITE ; Initialize it
  170. ;
  171. ; Don't clobber the Daylight Savings Time bit in register B, because we
  172. ; stash the LastKnownGood "environment variable" there.
  173. ;
  174. mov ax, 0bh
  175. CMOS_READ
  176. and al, 1
  177. mov ah, al
  178. or ah, REGISTER_B_ENABLE_PERIODIC_INTERRUPT
  179. mov al, 0bh
  180. CMOS_WRITE ; Initialize it
  181. mov al,0CH ; Register C
  182. CMOS_READ ; Read to initialize
  183. mov al,0DH ; Register D
  184. CMOS_READ ; Read to initialize
  185. stdCall _HalpReleaseCmosSpinLock
  186. epi_exit:
  187. stdRET _HalStartProfileInterrupt
  188. stdENDP _HalStartProfileInterrupt
  189. ;++
  190. ;
  191. ; HalStopProfileInterrupt(
  192. ; IN ULONG Reserved
  193. ; );
  194. ;
  195. ; Routine Description:
  196. ;
  197. ; What we do here is change the interrupt
  198. ; rate from the high profiling rate to the slowest thing we
  199. ; can get away with for PerformanceCounter rollover notification.
  200. ;
  201. ;--
  202. cPublicProc _HalStopProfileInterrupt ,1
  203. ;
  204. ; On the SystemPro there is only one profile device, so starting/stopping
  205. ; is only done from one processor.
  206. ;
  207. ; Note: This code uses PbNumber so it doesn't touch any SystemPro specific
  208. ; PCR value (so the code can be re-used by other hals)
  209. ;
  210. mov eax, PCR[PcPrcb]
  211. cmp byte ptr [eax].PbNumber, 0
  212. jne dpi_exit
  213. ;
  214. ; Turn off profiling hit computation and profile interrupt
  215. ;
  216. ;
  217. ; Don't clobber the Daylight Savings Time bit in register B, because we
  218. ; stash the LastKnownGood "environment variable" there.
  219. stdCall _HalpAcquireCmosSpinLock ; intr disabled
  220. mov ax, 0bh
  221. CMOS_READ
  222. and al, 1
  223. mov ah, al
  224. or ah, REGISTER_B_DISABLE_PERIODIC_INTERRUPT
  225. mov al, 0bh
  226. CMOS_WRITE ; Initialize it
  227. mov al,0CH ; Register C
  228. CMOS_READ ; dismiss pending profiling interrupt
  229. mov HalpProfilingStopped, 1
  230. stdCall _HalpReleaseCmosSpinLock
  231. dpi_exit:
  232. stdRET _HalStopProfileInterrupt
  233. stdENDP _HalStopProfileInterrupt
  234. ;++
  235. ; ULONG
  236. ; HalSetProfileInterval (
  237. ; ULONG Interval
  238. ; );
  239. ;
  240. ; Routine Description:
  241. ;
  242. ; This procedure sets the interrupt rate (and thus the sampling
  243. ; interval) for the profiling interrupt.
  244. ;
  245. ; If profiling is active (KiProfilingStopped == 0) the actual
  246. ; hardware interrupt rate will be set. Otherwise, a simple
  247. ; rate validation computation is done.
  248. ;
  249. ; Arguments:
  250. ;
  251. ; (TOS+4) - Interval in 100ns unit.
  252. ;
  253. ; Return Value:
  254. ;
  255. ; Interval actually used by system.
  256. ;--
  257. cPublicProc _HalSetProfileInterval ,1
  258. mov edx, [esp+4] ; [edx] = interval in 100ns unit
  259. and edx, 7FFFFFFFh ; Remove highest bit.
  260. mov ecx, 0 ; index = 0
  261. Hspi00:
  262. mov eax, ProfileIntervalTable[ecx * 4]
  263. cmp edx, eax ; if request interval < suport interval
  264. jbe short Hspi10 ; if be, find supported interval
  265. inc ecx
  266. jmp short Hspi00
  267. Hspi10:
  268. and eax, 7FFFFFFFh ; remove highest bit from supported interval
  269. jecxz short Hspi20 ; If first entry then use it
  270. push esi ; See which is closer to requested
  271. mov esi, eax ; rate - current entry, or preceeding
  272. sub esi, edx
  273. sub edx, ProfileIntervalTable[ecx * 4 - 4]
  274. cmp esi, edx
  275. pop esi
  276. jc short Hspi20
  277. dec ecx ; use preceeding entry
  278. mov eax, ProfileIntervalTable[ecx * 4]
  279. Hspi20:
  280. push eax ; save interval value
  281. mov al, ProfileIntervalInitTable[ecx]
  282. mov RegisterAProfileValue, al
  283. test HalpProfilingStopped,-1
  284. jnz short Hspi90
  285. stdCall _HalStartProfileInterrupt,<0> ; Re-start profile interrupt
  286. ; with the new interval
  287. Hspi90: pop eax
  288. stdRET _HalSetProfileInterval ; (eax) = cReturn interval
  289. stdENDP _HalSetProfileInterval
  290. page ,132
  291. subttl "System Profile Interrupt"
  292. ;++
  293. ;
  294. ; Routine Description:
  295. ;
  296. ; This routine is entered as the result of a profile interrupt.
  297. ; Its function is to dismiss the interrupt, raise system Irql to
  298. ; PROFILE_LEVEL and transfer control to
  299. ; the standard system routine to process any active profiles.
  300. ;
  301. ; Arguments:
  302. ;
  303. ; None
  304. ; Interrupt is disabled
  305. ;
  306. ; Return Value:
  307. ;
  308. ; Does not return, jumps directly to KeProfileInterrupt, which returns
  309. ;
  310. ; Sets Irql = PROFILE_LEVEL and dismisses the interrupt
  311. ;
  312. ;--
  313. ENTER_DR_ASSIST Hpi_a, Hpi_t
  314. cPublicProc _HalpProfileInterrupt ,0
  315. ;
  316. ; Save machine state in trap frame
  317. ;
  318. ENTER_INTERRUPT Hpi_a, Hpi_t
  319. ;
  320. ; (esp) - base of trap frame
  321. ;
  322. ; HalBeginSystemInterrupt must be called before any sti's
  323. ;
  324. ;
  325. push _IxProfileVector
  326. sub esp, 4 ; allocate space to save OldIrql
  327. stdCall _HalBeginSystemInterrupt, <PROFILE_LEVEL,_IxProfileVector,esp>
  328. or al,al ; check for spurious interrupt
  329. jz Hpi100
  330. ;
  331. ; If profiling not enabled, then don't ack device or count this interrupt.
  332. ; (this occurs during bootup when other processors sync PcStallScaleFactor)
  333. ;
  334. cmp HalpProfilingStopped,0
  335. jne short Hpi90
  336. ;
  337. ; On the SystemPro there is only one profile device, so the CMOS is only
  338. ; EOIed once.
  339. ;
  340. ; Note: This code uses PbNumber so it doesn't touch any SystemPro specific
  341. ; PCR value (so the code can be re-used by other hals)
  342. ;
  343. mov eax, PCR[PcPrcb]
  344. cmp byte ptr [eax].PbNumber, 0
  345. jne short _HalpProfileInterrupt2ndEntry@0
  346. ;
  347. ; This is the RTC interrupt, so we have to clear the
  348. ; interrupt flag on the RTC.
  349. ;
  350. stdCall _HalpAcquireCmosSpinLock
  351. ;
  352. ; clear interrupt flag on RTC by banging on the CMOS. On some systems this
  353. ; doesn't work the first time we do it, so we do it twice. It is rumored that
  354. ; some machines require more than this, but that hasn't been observed with NT.
  355. ;
  356. mov al,0CH ; Register C
  357. CMOS_READ ; Read to initialize
  358. mov al,0CH ; Register C
  359. CMOS_READ ; Read to initialize
  360. if DBG
  361. Hpi10: test al, 80h
  362. jz short Hpi15
  363. mov al,0CH ; Register C
  364. CMOS_READ ; Read to initialize
  365. jmp short Hpi10
  366. Hpi15:
  367. endif ; DBG
  368. stdCall _HalpReleaseCmosSpinLock
  369. ; This entry point is provided for symmetric multiprocessor HALs.
  370. ; Since it only makes sense for one processor to clear the CMOS,
  371. ; all other processors can instead jmp into this entry point.
  372. ;
  373. align 4
  374. public _HalpProfileInterrupt2ndEntry@0
  375. _HalpProfileInterrupt2ndEntry@0:
  376. stdCall _KeProfileInterrupt,<ebp> ; (ebp) = trap frame
  377. Hpi90:
  378. INTERRUPT_EXIT
  379. Hpi100:
  380. add esp, 8 ; spurious, no EndOfInterrupt
  381. SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
  382. stdENDP _HalpProfileInterrupt
  383. _TEXT ends
  384. end