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.

726 lines
17 KiB

  1. /*++
  2. Module Name:
  3. i64clock.c
  4. Abstract:
  5. Author:
  6. Bernard Lint, M. Jayakumar
  7. Ron Mosgrove - Intel
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. Based on halmps/mpclockc.c
  12. --*/
  13. #include "halp.h"
  14. extern ULONG HalpNextRate;
  15. extern BOOLEAN HalpClockSetMSRate;
  16. int _fltused;
  17. BOOLEAN ReadPerfMonCounter = FALSE;
  18. ULONG HalpCPUMHz;
  19. #if defined(INSTRUMENT_CLOCK_DRIFT)
  20. ULONGLONG HalpITMSkew;
  21. ULONG HalpCountBadITMValues;
  22. ULONGLONG HalpMinITMMissed;
  23. ULONGLONG HalpMaxITMMissed;
  24. ULONG HalpBreakMissedTickMin;
  25. ULONG HalpBreakMissedTickMax = ~0U;
  26. BOOLEAN HalpResetITMDebug;
  27. #endif
  28. #if DBG
  29. // Thierry - until compiler supports the generation of enum types in pdbs...
  30. // At that time, we will be able the use the enums instead of globals.
  31. unsigned int HalpDpfltrMaxMask = HALIA64_DPFLTR_MAXMASK;
  32. ULONG HalpTimeOverflows;
  33. #endif // DBG
  34. ULONGLONG HalpITCFrequency = 500000000; // 500MHz for default real hardware power on.
  35. ULONGLONG HalpProcessorFrequency = 500000000; // 500MHz CPU
  36. //
  37. // Ticks per 100ns used to compute ITM update count
  38. //
  39. double HalpITCTicksPer100ns;
  40. ULONGLONG HalpClockCount;
  41. //
  42. // HalpSetNextClockInterrupt():
  43. // move to cr.itm latency (= 40 cycles) + 2 cycles from the itc read.
  44. //
  45. ULONGLONG HalpITMUpdateLatency = 42;
  46. //
  47. // HalpSetNextClockInterrupt() uses this as the minimum time before the next
  48. // interrupt. If the next interrupt would occur too soon then the next
  49. // interrupt will be scheduled another HalpClockCount ITC ticks.
  50. //
  51. ULONGLONG HalpITMMinimumUpdate;
  52. //
  53. // All of these are in 100ns units
  54. //
  55. ULONGLONG HalpCurrentTimeIncrement = DEFAULT_CLOCK_INTERVAL;
  56. ULONGLONG HalpNextTimeIncrement = DEFAULT_CLOCK_INTERVAL;
  57. ULONGLONG HalpNewTimeIncrement = DEFAULT_CLOCK_INTERVAL;
  58. ULONGLONG // = (current ITC - previous ITM)
  59. HalpSetNextClockInterrupt(
  60. ULONGLONG PreviousITM
  61. );
  62. #ifdef ALLOC_PRAGMA
  63. #pragma alloc_text(INIT,HalpSetInitialClockRate)
  64. #pragma alloc_text(INIT,HalpInitializeTimerResolution)
  65. #endif
  66. VOID
  67. HalpClearClock (
  68. )
  69. /*++
  70. Routine Description:
  71. Set clock to zero.
  72. Return Value:
  73. None.
  74. --*/
  75. {
  76. HalpWriteITC(0);
  77. HalpWriteITM(0);
  78. return;
  79. }
  80. VOID
  81. HalpInitializeClock (
  82. VOID
  83. )
  84. /*++
  85. Routine Description:
  86. Initialize system time clock (ITC and ITM) to generate an interrupt
  87. at every 10 ms interval at ITC_CLOCK_VECTOR.
  88. Previously this routine initialize system time clock using 8254 timer1
  89. counter 0 to generate an interrupt at every 15ms interval at 8259 irq0.
  90. See the definitions of TIME_INCREMENT and ROLLOVER_COUNT if clock rate
  91. needs to be changed.
  92. Arguments:
  93. None
  94. Return Value:
  95. None.
  96. --*/
  97. {
  98. HalpSetInitialClockRate();
  99. HalpClearClock();
  100. HalpWriteITM(PCR->HalReserved[CURRENT_ITM_VALUE_INDEX]);
  101. return;
  102. }
  103. VOID
  104. HalpInitializeClockPn (
  105. VOID
  106. )
  107. /*++
  108. Routine Description:
  109. Assumes that only non-BSP processors call this routine.
  110. Initializes system time clock (ITC and ITM) to generate an interrupt
  111. at every 10 ms interval at ITC_CLOCK_VECTOR.
  112. Previously this routine initialize system time clock using 8254 timer1
  113. counter 0 to generate an interrupt at every 15ms interval at 8259 irq0.
  114. See the definitions of TIME_INCREMENT and ROLLOVER_COUNT if clock rate
  115. needs to be changed.
  116. Arguments:
  117. None
  118. Return Value:
  119. None.
  120. --*/
  121. {
  122. ULONGLONG itmValue;
  123. itmValue = (ULONGLONG)(HalpITCTicksPer100ns * MAXIMUM_CLOCK_INTERVAL);
  124. PCR->HalReserved[CURRENT_ITM_VALUE_INDEX] = itmValue;
  125. HalpClearClock();
  126. HalpWriteITM( itmValue );
  127. return;
  128. }
  129. VOID
  130. HalpSetInitialClockRate (
  131. VOID
  132. )
  133. /*++
  134. Routine Description:
  135. This function is called to set the initial clock interrupt rate
  136. Assumes that only the BSP processor calls this routine.
  137. Arguments:
  138. None
  139. Return Value:
  140. None
  141. --*/
  142. {
  143. //
  144. // CPU Frequency in MHz = ticks per second / 10 ** 6
  145. //
  146. HalpCPUMHz = (ULONG)((HalpProcessorFrequency + 500000) / 1000000);
  147. //
  148. // Ticks per 100ns = ticks per second / 10 ** 7
  149. //
  150. HalpITCTicksPer100ns = (double) HalpITCFrequency / (10000000.);
  151. if (HalpITCTicksPer100ns < 1) {
  152. HalpITCTicksPer100ns = 1;
  153. }
  154. HalpClockCount = (ULONGLONG)(HalpITCTicksPer100ns * MAXIMUM_CLOCK_INTERVAL);
  155. HalpITMMinimumUpdate = HalpClockCount >> 3;
  156. PCR->HalReserved[CURRENT_ITM_VALUE_INDEX] = HalpClockCount;
  157. KeSetTimeIncrement(MAXIMUM_CLOCK_INTERVAL, MINIMUM_CLOCK_INTERVAL);
  158. }
  159. VOID
  160. HalpClockInterrupt (
  161. IN PKINTERRUPT_ROUTINE Interrupt,
  162. IN PKTRAP_FRAME TrapFrame
  163. )
  164. /*++
  165. Routine Description:
  166. System Clock Interrupt Handler, for P0 processor only.
  167. N.B. Assumptions: Comes with IRQL set to CLOCK_LEVEL to disable
  168. interrupts.
  169. Arguments:
  170. TrapFrame - Trap frame address.
  171. Return Value:
  172. None.
  173. --*/
  174. {
  175. ULONGLONG currentITC;
  176. ULONGLONG currentITCDelta;
  177. ULONGLONG elapsedTimeIn100ns;
  178. #if defined(INSTRUMENT_CLOCK_DRIFT)
  179. ULONGLONG currentITM, excessITM;
  180. #endif
  181. ULONGLONG previousITM;
  182. LONG mcaNotification;
  183. //
  184. // Check to see if a clock interrupt is generated in a small latency window
  185. // in HalpSetNextClockInterrupt.
  186. //
  187. if ((LONGLONG)(PCR->HalReserved[CURRENT_ITM_VALUE_INDEX] - HalpReadITC()) > 0)
  188. {
  189. return;
  190. }
  191. //
  192. // PerfMon: Per P0 clock interrupt PMD4 collection.
  193. //
  194. if (ReadPerfMonCounter) {
  195. ULONGLONG currentPerfMonValue;
  196. currentPerfMonValue = HalpReadPerfMonDataReg4();
  197. HalDebugPrint(( HAL_INFO, "\nHAL: HalpClockInterrupt - PMD4=%I64x\n", currentPerfMonValue ));
  198. }
  199. //
  200. // Calculate the number of ticks that have gone by since the Interrupt
  201. // was supposed to fire. If it is a small number of ticks we will do the
  202. // calculation in HalpSetNextClockInterrupt and avoid the multiply and
  203. // divide.
  204. //
  205. previousITM = (ULONGLONG)PCR->HalReserved[CURRENT_ITM_VALUE_INDEX];
  206. currentITC = HalpReadITC();
  207. if ((currentITC - previousITM) > (HalpClockCount << 2)) {
  208. currentITCDelta = (currentITC - previousITM) / HalpClockCount * HalpClockCount;
  209. previousITM += currentITCDelta;
  210. } else {
  211. currentITCDelta = 0;
  212. }
  213. //
  214. // Set next clock interrupt, based on ITC and
  215. // increment ITM, accounting for interrupt latency.
  216. //
  217. currentITCDelta += HalpSetNextClockInterrupt(previousITM);
  218. #if defined(INSTRUMENT_CLOCK_DRIFT)
  219. //
  220. // Time the next interrupt is scheduled to occur
  221. //
  222. currentITM = (ULONGLONG)PCR->HalReserved[CURRENT_ITM_VALUE_INDEX];
  223. excessITM = (currentITM - previousITM) / HalpClockCount - 1;
  224. if (excessITM != 0) {
  225. if (HalpMinITMMissed == 0 || excessITM < HalpMinITMMissed) {
  226. HalpMinITMMissed = excessITM;
  227. }
  228. if (excessITM > HalpMaxITMMissed) {
  229. HalpMaxITMMissed = excessITM;
  230. }
  231. HalpCountBadITMValues++;
  232. HalpITMSkew += excessITM;
  233. if (HalpBreakMissedTickMin != 0 &&
  234. HalpBreakMissedTickMin <= excessITM &&
  235. HalpBreakMissedTickMax >= excessITM &&
  236. !HalpResetITMDebug) {
  237. DbgBreakPoint();
  238. }
  239. }
  240. if (HalpResetITMDebug) {
  241. HalpResetITMDebug = FALSE;
  242. HalpCountBadITMValues = 0;
  243. HalpITMSkew = 0;
  244. HalpMinITMMissed = 0;
  245. HalpMaxITMMissed = 0;
  246. }
  247. #endif
  248. //
  249. // Call the kernel to update system time.
  250. // P0 updates System time and Run Time.
  251. //
  252. elapsedTimeIn100ns = (ULONGLONG) (currentITCDelta/HalpITCTicksPer100ns);
  253. elapsedTimeIn100ns += HalpCurrentTimeIncrement;
  254. //
  255. // KeUpdateSystemTime takes a ULONG which is actually used as a LONG. This
  256. // overflows after 214 seconds. Since everytime we break into the debugger
  257. // that is exceeded we will cap it at something more reasonable.
  258. //
  259. if (elapsedTimeIn100ns > CLOCK_UPDATE_THRESHOLD) {
  260. elapsedTimeIn100ns = CLOCK_UPDATE_THRESHOLD;
  261. #if DBG
  262. HalpTimeOverflows++;
  263. #endif
  264. }
  265. KeUpdateSystemTime(TrapFrame, (ULONG)elapsedTimeIn100ns);
  266. HalpCurrentTimeIncrement = HalpNextTimeIncrement;
  267. HalpNextTimeIncrement = HalpNewTimeIncrement;
  268. //
  269. // If MCA notification was requested by MCA Handler, execute it.
  270. //
  271. mcaNotification = InterlockedExchange( &HalpMcaInfo.DpcNotification, 0 );
  272. if ( mcaNotification ) {
  273. if ( HalpMcaInfo.KernelDelivery ) {
  274. if ( !HalpMcaInfo.KernelDelivery( HalpMcaInfo.KernelToken, McaAvailable, NULL ) ) {
  275. InterlockedIncrement( &HalpMcaInfo.Stats.KernelDeliveryFails );
  276. }
  277. }
  278. if ( HalpMcaInfo.DriverInfo.DpcCallback ) {
  279. if ( !KeInsertQueueDpc( &HalpMcaInfo.DriverDpc, NULL, NULL ) ) {
  280. InterlockedIncrement( &HalpMcaInfo.Stats.DriverDpcQueueFails );
  281. }
  282. }
  283. }
  284. //
  285. // Poll for debugger breakin if enabled.
  286. //
  287. if ( KdDebuggerEnabled ) {
  288. if ((PCR->PollSlot == PCR->Number) && KdPollBreakIn() ) {
  289. KeBreakinBreakpoint();
  290. }
  291. PCR->PollSlot++;
  292. if (PCR->PollSlot >= KeNumberProcessors) {
  293. PCR->PollSlot = 0;
  294. }
  295. }
  296. } // HalpClockInterrupt()
  297. VOID
  298. HalpClockInterruptPn (
  299. IN PKINTERRUPT_ROUTINE Interrupt,
  300. IN PKTRAP_FRAME TrapFrame
  301. )
  302. /*++
  303. Routine Description:
  304. System Clock Interrupt Handler, for processors other than P0.
  305. N.B. Assumptions: Comes with IRQL set to CLOCK_LEVEL to disable
  306. interrupts.
  307. Arguments:
  308. TrapFrame - Trap frame address.
  309. Return Value:
  310. None.
  311. --*/
  312. {
  313. ULONGLONG previousITM, currentITC;
  314. //
  315. // Calculate the number of ticks that have gone by since the Interrupt
  316. // was supposed to fire. It is easier to do this in C than asm.
  317. //
  318. previousITM = (ULONGLONG)PCR->HalReserved[CURRENT_ITM_VALUE_INDEX];
  319. currentITC = HalpReadITC();
  320. if ((currentITC - previousITM) > (HalpClockCount << 2)) {
  321. previousITM += (currentITC - previousITM) / HalpClockCount * HalpClockCount;
  322. }
  323. //
  324. // Set next clock interrupt, based on ITC and
  325. // increment ITM, accounting for interrupt latency.
  326. //
  327. (void)HalpSetNextClockInterrupt(previousITM);
  328. //
  329. // Call the kernel to update run time.
  330. // Pn updates only Run time.
  331. //
  332. KeUpdateRunTime(TrapFrame);
  333. // IA64 MCA Notification - 09/18/2000 - WARNING
  334. // If faster MCA notification was required, the BSP MCA notification checking
  335. // should be placed here.
  336. //
  337. //
  338. // Poll for debugger breakin if enabled.
  339. //
  340. if ( KdDebuggerEnabled ) {
  341. if ((PCR->PollSlot == PCR->Number) && KdPollBreakIn() ) {
  342. KeBreakinBreakpoint();
  343. }
  344. PCR->PollSlot++;
  345. if (PCR->PollSlot >= KeNumberProcessors) {
  346. PCR->PollSlot = 0;
  347. }
  348. }
  349. } // HalpClockInterruptPn()
  350. VOID
  351. HalpInitializeClockInterrupts (
  352. VOID
  353. )
  354. {
  355. PKPRCB Prcb;
  356. UCHAR InterruptVector;
  357. ULONGLONG ITVData;
  358. Prcb = PCR->Prcb;
  359. InterruptVector = CLOCK_LEVEL << VECTOR_IRQL_SHIFT;
  360. if (Prcb->Number == 0) {
  361. HalpSetInternalVector(InterruptVector, HalpClockInterrupt);
  362. } else {
  363. //
  364. // Non-BSP processor
  365. //
  366. HalpSetInternalVector(InterruptVector, HalpClockInterruptPn);
  367. }
  368. ITVData = (ULONGLONG) InterruptVector;
  369. HalpWriteITVector(ITVData);
  370. return;
  371. }
  372. ULONG
  373. HalSetTimeIncrement (
  374. IN ULONG DesiredIncrement
  375. )
  376. /*++
  377. Routine Description:
  378. This function is called to set the clock interrupt rate to the frequency
  379. required by the specified time increment value.
  380. N.B. This function is only executed on the processor that keeps the
  381. system time. Previously this was called HalpSetTimeIncrement. We
  382. have renamed it HalSetTimeIncrement.
  383. Arguments:
  384. DesiredIncrement - Supplies desired number of 100ns units between clock
  385. interrupts.
  386. Return Value:
  387. The actual time increment in 100ns units.
  388. --*/
  389. {
  390. ULONGLONG NextIntervalCount;
  391. KIRQL OldIrql;
  392. //
  393. // DesiredIncrement must map within the acceptable range.
  394. //
  395. if (DesiredIncrement < MINIMUM_CLOCK_INTERVAL)
  396. DesiredIncrement = MINIMUM_CLOCK_INTERVAL;
  397. else if (DesiredIncrement > MAXIMUM_CLOCK_INTERVAL)
  398. DesiredIncrement = MAXIMUM_CLOCK_INTERVAL;
  399. //
  400. // Raise IRQL to the highest level, set the new clock interrupt
  401. // parameters, lower IRQl, and return the new time increment value.
  402. //
  403. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  404. //
  405. // Calculate the actual 64 bit time value which forms the target interval.
  406. // The resulting value is added to the ITC to form the new ITM value.
  407. // HalpITCTicksPer100ns is the calibrated value for the ITC whose value
  408. // works out to be 100ns (or as close as we can come).
  409. // Previously HalpITCTicksPer100ns was called as HalpPerformanceFrequency
  410. //
  411. NextIntervalCount = (ULONGLONG)(HalpITCTicksPer100ns * DesiredIncrement);
  412. //
  413. // Calculate the number of 100ns units to report to the kernel every
  414. // time the ITM matches the ITC with this new period. Note, for small
  415. // values of DesiredIncrement (min being 10000, ie 1ms), truncation
  416. // in the above may result in a small decrement in the 5th decimal
  417. // place. As we are effectively dealing with a 4 digit number, eg
  418. // 10000 becomes 9999.something, we really can't do any better than
  419. // the following.
  420. //
  421. HalpClockCount = NextIntervalCount;
  422. HalpNewTimeIncrement = DesiredIncrement;
  423. //
  424. // HalpClockSetMSRate = TRUE;
  425. //
  426. KeLowerIrql(OldIrql);
  427. return DesiredIncrement;
  428. }
  429. NTSTATUS
  430. HalpQueryFrequency(
  431. PULONGLONG ITCFrequency,
  432. PULONGLONG ProcessorFrequency
  433. )
  434. /*++
  435. Routine Description:
  436. This function is called to provide the ITC update rate.
  437. This value is computed by first getting the platform base frequency
  438. from the SAL_FREQ_BASE call. Then applying on the return value, the
  439. ITC ratios obtained from the PAL_FREQ_RATIOS call.
  440. Arguments:
  441. None.
  442. Return Value:
  443. ULONGLONG ITCFrequency - number of ITC updates per seconds
  444. --*/
  445. {
  446. ULONG ITCRatioDenominator = 0;
  447. ULONG ITCRatioNumerator = 0;
  448. ULONG ProcessorRatioDenominator = 0;
  449. ULONG ProcessorRatioNumerator = 0;
  450. SAL_PAL_RETURN_VALUES SalReturn = {0};
  451. SAL_PAL_RETURN_VALUES PalReturn = {0};
  452. SAL_STATUS SalStatus;
  453. PAL_STATUS PalStatus;
  454. SalStatus = HalpSalCall(SAL_FREQ_BASE,
  455. 0 /* Platform base clock frequency is the clock input to the processor */,
  456. 0,
  457. 0,
  458. 0,
  459. 0,
  460. 0,
  461. 0,
  462. &SalReturn);
  463. if (SalStatus != 0) {
  464. HalDebugPrint(( HAL_ERROR,
  465. "HAL: HalInitSystem - Phase1 SAL_FREQ_BASE is returning error # %d\n",
  466. SalStatus ));
  467. return STATUS_UNSUCCESSFUL;
  468. }
  469. HalDebugPrint(( HAL_INFO, "HAL: HalInitSystem - Platform base clock Frequency is %I64u\n",SalReturn.ReturnValues[1] ));
  470. PalStatus = HalpPalCall( PAL_FREQ_RATIOS,
  471. 0,
  472. 0,
  473. 0,
  474. &PalReturn);
  475. if (PalStatus != 0) {
  476. HalDebugPrint(( HAL_ERROR,
  477. "HAL: HalInitSystem - Phase1 PAL_FREQ_RATIOS is returning error # %d\n",
  478. PalStatus ));
  479. return STATUS_UNSUCCESSFUL;
  480. }
  481. ProcessorRatioNumerator = (ULONG)((PalReturn.ReturnValues[1]) >> 32);
  482. ProcessorRatioDenominator = (ULONG)( PalReturn.ReturnValues[1]);
  483. HalDebugPrint(( HAL_INFO,
  484. "HAL: HalInitSystem - PAL returns Processor to Platform clock Frequency as %lu : %lu\n",
  485. ProcessorRatioNumerator,
  486. ProcessorRatioDenominator));
  487. *ProcessorFrequency = SalReturn.ReturnValues[1] * ProcessorRatioNumerator / ProcessorRatioDenominator;
  488. HalDebugPrint(( HAL_INFO,
  489. "HAL: HalInitSystem - Processor clock Frequency is %I64u \n",
  490. ProcessorFrequency ));
  491. ITCRatioNumerator = (ULONG)((PalReturn.ReturnValues[3]) >> 32);
  492. ITCRatioDenominator = (ULONG)( PalReturn.ReturnValues[3]);
  493. HalDebugPrint(( HAL_INFO,
  494. "HAL: HalInitSystem - PAL returns ITC to Platform clock Frequency as %lu : %lu\n",
  495. ITCRatioNumerator,
  496. ITCRatioDenominator));
  497. *ITCFrequency = SalReturn.ReturnValues[1] * ITCRatioNumerator / ITCRatioDenominator;
  498. HalDebugPrint(( HAL_INFO,
  499. "HAL: HalInitSystem - ITC clock Frequency is %I64u \n",
  500. ITCFrequency ));
  501. return STATUS_SUCCESS;
  502. }