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.

434 lines
8.7 KiB

  1. //
  2. // No Check-in Source Code.
  3. //
  4. // Do not make this code available to non-Microsoft personnel
  5. // without Intel's express permission
  6. //
  7. /**
  8. *** Copyright (C) 1996-97 Intel Corporation. All rights reserved.
  9. ***
  10. *** The information and source code contained herein is the exclusive
  11. *** property of Intel Corporation and may not be disclosed, examined
  12. *** or reproduced in whole or in part without explicit written authorization
  13. *** from the company.
  14. **/
  15. /*++
  16. Copyright (c) 1995 Intel Corporation
  17. Module Name:
  18. simtimer.c
  19. Abstract:
  20. This module implements the routines to provide timer (both
  21. interval and profile) interrupt support.
  22. Author:
  23. 14-Apr-1995
  24. Environment:
  25. Kernel mode
  26. Revision History:
  27. --*/
  28. #include "halp.h"
  29. #include <ssc.h>
  30. ULONGLONG
  31. HalpUpdateITM(
  32. IN ULONGLONG HalpClockCount
  33. );
  34. ULONG
  35. HalpSetTimeIncrement (
  36. IN ULONG DesiredIncrement
  37. );
  38. __declspec(dllimport)
  39. BOOLEAN
  40. KdPollBreakIn(
  41. VOID
  42. );
  43. ULONGLONG HalpPerformanceFrequency;
  44. static ULONGLONG HalpClockCount;
  45. static ULONG HalpCurrentTimeIncrement = DEFAULT_CLOCK_INTERVAL;
  46. static ULONG HalpNextTimeIncrement = DEFAULT_CLOCK_INTERVAL;
  47. static ULONG HalpNewTimeIncrement = DEFAULT_CLOCK_INTERVAL;
  48. #define GAMBIT 1
  49. #ifdef GAMBIT
  50. ULONG HalpKdPollDelayCount = 0;
  51. #endif
  52. static ULONG_PTR HalpProfileInterval = (ULONG_PTR)DEFAULT_PROFILE_INTERVAL;
  53. static BOOLEAN HalpProfileStopped = TRUE;
  54. ULONG
  55. HalSetTimeIncrement (
  56. IN ULONG DesiredIncrement
  57. )
  58. /*++
  59. Routine Description:
  60. This routine initialize system time clock to generate an
  61. interrupt at every DesiredIncrement interval. It calls the
  62. SSC function SscSetPeriodicInterruptInterval to set the new
  63. interval. The new interval takes effect after the next timer
  64. interval interrupt is deliverd.
  65. Arguments:
  66. DesiredIncrement - desired interval between every timer tick (in 100ns unit.)
  67. Return Value:
  68. The time increment set.
  69. --*/
  70. {
  71. SscSetPeriodicInterruptInterval (
  72. SSC_CLOCK_TIMER_INTERRUPT,
  73. 100 * DesiredIncrement
  74. );
  75. HalpNextTimeIncrement = DesiredIncrement;
  76. HalpSetTimeIncrement(DesiredIncrement);
  77. return DesiredIncrement;
  78. }
  79. VOID
  80. HalStartProfileInterrupt(
  81. IN KPROFILE_SOURCE ProfileSource
  82. )
  83. /*++
  84. Routine Description:
  85. This routine calls SscSetPeriodicInterruptInterval to request
  86. the simulator to send profile timer interrupt to the OS at the
  87. interval specified by HalpProfileInterval.
  88. It also sets HalpProfileStopped to FALSE.
  89. Arguments:
  90. Reserved
  91. Return Value:
  92. Returns nothing.
  93. --*/
  94. {
  95. SscSetPeriodicInterruptInterval (
  96. SSC_PROFILE_TIMER_INTERRUPT,
  97. 100 * (ULONG)HalpProfileInterval
  98. );
  99. HalpProfileStopped = FALSE;
  100. }
  101. VOID
  102. HalStopProfileInterrupt(
  103. IN KPROFILE_SOURCE ProfileSource
  104. )
  105. /*++
  106. Routine Description:
  107. What we do here is change the interrupt interval to 0.
  108. Essentially, the simulator stop sending profile timer
  109. interrupts to the OS.
  110. It also sets HalpProfileStopped to TRUE.
  111. Arguments:
  112. Reserved
  113. Return Value:
  114. Returns nothing.
  115. --*/
  116. {
  117. SscSetPeriodicInterruptInterval (SSC_PROFILE_TIMER_INTERRUPT, 0);
  118. HalpProfileStopped = TRUE;
  119. }
  120. ULONG_PTR
  121. HalSetProfileInterval(
  122. IN ULONG_PTR Interval
  123. )
  124. /*++
  125. Routine Description:
  126. This procedure sets the interrupt rate (and thus the sampling
  127. interval) for the profiling interrupt.
  128. If profiling is active (HalpProfileStopped == FALSE), the SSC
  129. function SscSetPeriodicInterruptInterval is called to set the
  130. new profile timer interrupt interval.
  131. Otherwise, a simple rate validation computation is done.
  132. Arguments:
  133. Interval - Time interval in 100ns units.
  134. Return Value:
  135. Time interval actually used by the system.
  136. --*/
  137. {
  138. //
  139. // If the specified profile interval is less that the minimum profile
  140. // interval or greater than the maximum profile interval, then set the
  141. // profile interval to the minimum or maximum as appropriate.
  142. //
  143. //
  144. // Check to see if the Desired Interval is reasonable, if not adjust it.
  145. // We can probably remove this check once we've verified everything works
  146. // as anticipated.
  147. //
  148. if (Interval > MAXIMUM_PROFILE_INTERVAL) {
  149. HalpProfileInterval = MAXIMUM_PROFILE_INTERVAL;
  150. } else if (Interval < MINIMUM_PROFILE_INTERVAL) {
  151. HalpProfileInterval = MINIMUM_PROFILE_INTERVAL;
  152. } else {
  153. HalpProfileInterval = Interval;
  154. }
  155. //
  156. // Profiling is active. Make the new interrupt interval effective.
  157. //
  158. if (!HalpProfileStopped) {
  159. SscSetPeriodicInterruptInterval (
  160. SSC_PROFILE_TIMER_INTERRUPT,
  161. 100 * (ULONG)HalpProfileInterval
  162. );
  163. }
  164. return HalpProfileInterval;
  165. }
  166. VOID
  167. HalpClockInterrupt (
  168. IN PKINTERRUPT_ROUTINE Interrupt,
  169. IN PKTRAP_FRAME TrapFrame
  170. )
  171. /*++
  172. Routine Description:
  173. System Clock Interrupt Handler, for P0 processor only.
  174. N.B. Assumptions: Comes with IRQL set to CLOCK_LEVEL to disable
  175. interrupts.
  176. Arguments:
  177. TrapFrame - Trap frame address.
  178. Return Value:
  179. None.
  180. --*/
  181. {
  182. //
  183. // Call the kernel to update system time.
  184. // P0 updates System time and Run Time.
  185. //
  186. KeUpdateSystemTime(TrapFrame,HalpCurrentTimeIncrement);
  187. HalpCurrentTimeIncrement = HalpNextTimeIncrement;
  188. HalpNextTimeIncrement = HalpNewTimeIncrement;
  189. //
  190. // Increment ITM, accounting for interrupt latency.
  191. //
  192. HalpUpdateITM(HalpClockCount);
  193. #ifdef GAMBIT
  194. if (!HalpKdPollDelayCount) {
  195. HalpKdPollDelayCount = 4;
  196. #endif
  197. if ( KdDebuggerEnabled && KdPollBreakIn() )
  198. KeBreakinBreakpoint();
  199. #ifdef GAMBIT
  200. } else {
  201. HalpKdPollDelayCount--;
  202. }
  203. #endif
  204. }
  205. VOID
  206. HalpClockInterruptPn (
  207. IN PKINTERRUPT_ROUTINE Interrupt,
  208. IN PKTRAP_FRAME TrapFrame
  209. )
  210. /*++
  211. Routine Description:
  212. System Clock Interrupt Handler, for processors other than P0.
  213. N.B. Assumptions: Comes with IRQL set to CLOCK_LEVEL to disable
  214. interrupts.
  215. Arguments:
  216. TrapFrame - Trap frame address.
  217. Return Value:
  218. None.
  219. --*/
  220. {
  221. //
  222. // Call the kernel to update run time.
  223. // Pn updates only Run time.
  224. //
  225. KeUpdateRunTime(TrapFrame);
  226. //
  227. // Increment ITM, accounting for interrupt latency.
  228. //
  229. HalpUpdateITM(HalpClockCount);
  230. }
  231. VOID
  232. HalpProfileInterrupt (
  233. IN PKTRAP_FRAME TrapFrame
  234. )
  235. /*++
  236. Routine Description:
  237. System Profile Interrupt Handler.
  238. Arguments:
  239. TrapFrame - Trap frame address.
  240. Return Value:
  241. None.
  242. --*/
  243. {
  244. // KeProfileInterrupt (TrapFrame);
  245. }
  246. ULONG
  247. HalpSetTimeIncrement (
  248. IN ULONG DesiredIncrement
  249. )
  250. /*++
  251. Routine Description:
  252. This function is called to set the clock interrupt rate to the frequency
  253. required by the specified time increment value.
  254. N.B. This function is only executed on the processor that keeps the
  255. system time.
  256. This function should eventually become the HalSetTimeIncrement once
  257. we actually start using the ITC/ITM. Not currently supported by the
  258. simulator.
  259. Arguments:
  260. DesiredIncrement - Supplies desired number of 100ns units between clock
  261. interrupts.
  262. Return Value:
  263. The actual time increment in 100ns units.
  264. --*/
  265. {
  266. ULONGLONG NextIntervalCount;
  267. KIRQL OldIrql;
  268. //
  269. // DesiredIncrement must map within the acceptable range.
  270. //
  271. if (DesiredIncrement < MINIMUM_CLOCK_INTERVAL)
  272. DesiredIncrement = MINIMUM_CLOCK_INTERVAL;
  273. else if (DesiredIncrement > MAXIMUM_CLOCK_INTERVAL)
  274. DesiredIncrement = MAXIMUM_CLOCK_INTERVAL;
  275. //
  276. // Raise IRQL to the highest level, set the new clock interrupt
  277. // parameters, lower IRQl, and return the new time increment value.
  278. //
  279. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  280. //
  281. // Calculate the actual 64 bit time value which forms the target interval.
  282. // The resulting value is added to the ITC to form the new ITM value.
  283. // HalpPerformanceFrequency is the calibrated value for the ITC whose value
  284. // works out to be 100ns (or as close as we can come).
  285. //
  286. NextIntervalCount = HalpPerformanceFrequency * DesiredIncrement;
  287. //
  288. // Calculate the number of 100ns units to report to the kernel every
  289. // time the ITM matches the ITC with this new period. Note, for small
  290. // values of DesiredIncrement (min being 10000, ie 1ms), truncation
  291. // in the above may result in a small decrement in the 5th decimal
  292. // place. As we are effectively dealing with a 4 digit number, eg
  293. // 10000 becomes 9999.something, we really can't do any better than
  294. // the following.
  295. //
  296. HalpClockCount = NextIntervalCount;
  297. HalpNewTimeIncrement = DesiredIncrement;
  298. KeLowerIrql(OldIrql);
  299. return DesiredIncrement;
  300. }