3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halamd64/generic/tsc.c
5 * PURPOSE: HAL Routines for TSC handling
6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
9 /* INCLUDES ******************************************************************/
17 LARGE_INTEGER HalpCpuClockFrequency
= {{INITIAL_STALL_COUNT
* 1000000}};
19 UCHAR TscCalibrationPhase
;
20 ULONG64 TscCalibrationArray
[NUM_SAMPLES
];
21 UCHAR HalpRtcClockVector
= 0xD1;
23 #define RTC_MODE 6 /* Mode 6 is 1024 Hz */
24 #define SAMPLE_FREQENCY ((32768 << 1) >> RTC_MODE)
26 /* PRIVATE FUNCTIONS *********************************************************/
37 /* Calculate the sum of the squares of X */
38 SumXX
= (XMax
* (XMax
+ 1) * (2*XMax
+ 1)) / 6;
40 /* Calculate the sum of the differences to the first value
42 for (SumXY
= 0, X
= 1; X
<= XMax
; X
++)
44 SumXY
+= X
* (ArrayY
[X
] - ArrayY
[0]);
47 /* Account for sample frequency */
48 SumXY
*= SAMPLE_FREQENCY
;
50 /* Return the quotient of the sums */
51 return (SumXY
+ (SumXX
/2)) / SumXX
;
56 HalpInitializeTsc(VOID
)
59 KIDTENTRY OldIdtEntry
, *IdtPointer
;
60 PKPCR Pcr
= KeGetPcr();
61 UCHAR RegisterA
, RegisterB
;
63 /* Check if the CPU supports RDTSC */
64 if (!(KeGetCurrentPrcb()->FeatureBits
& KF_RDTSC
))
66 KeBugCheck(HAL_INITIALIZATION_FAILED
);
69 /* Save flags and disable interrupts */
70 Flags
= __readeflags();
73 /* Enable the periodic interrupt in the CMOS */
74 RegisterB
= HalpReadCmos(RTC_REGISTER_B
);
75 HalpWriteCmos(RTC_REGISTER_B
, RegisterB
| RTC_REG_B_PI
);
77 /* Modify register A to RTC_MODE to get SAMPLE_FREQENCY */
78 RegisterA
= HalpReadCmos(RTC_REGISTER_A
);
79 RegisterA
= (RegisterA
& 0xF0) | RTC_MODE
;
80 HalpWriteCmos(RTC_REGISTER_A
, RegisterA
);
82 /* Save old IDT entry */
83 IdtPointer
= KiGetIdtEntry(Pcr
, HalpRtcClockVector
);
84 OldIdtEntry
= *IdtPointer
;
86 /* Set the calibration ISR */
87 KeRegisterInterruptHandler(HalpRtcClockVector
, TscCalibrationISR
);
89 /* Reset TSC value to 0 */
90 __writemsr(MSR_RDTSC
, 0);
92 /* Enable the timer interupt */
93 HalEnableSystemInterrupt(HalpRtcClockVector
, CLOCK_LEVEL
, Latched
);
95 /* Read register C, so that the next interrupt can happen */
96 HalpReadCmos(RTC_REGISTER_C
);;
98 /* Wait for completion */
100 while (TscCalibrationPhase
< NUM_SAMPLES
) _ReadWriteBarrier();
103 /* Disable the periodic interrupt in the CMOS */
104 HalpWriteCmos(RTC_REGISTER_B
, RegisterB
& ~RTC_REG_B_PI
);
106 /* Disable the timer interupt */
107 HalDisableSystemInterrupt(HalpRtcClockVector
, CLOCK_LEVEL
);
109 /* Restore old IDT entry */
110 *IdtPointer
= OldIdtEntry
;
112 /* Calculate an average, using simplified linear regression */
113 HalpCpuClockFrequency
.QuadPart
= DoLinearRegression(NUM_SAMPLES
- 1,
114 TscCalibrationArray
);
117 __writeeflags(Flags
);
123 HalpCalibrateStallExecution(VOID
)
125 // Timer interrupt is now active
129 KeGetPcr()->StallScaleFactor
= (ULONG
)(HalpCpuClockFrequency
.QuadPart
/ 1000000);
132 /* PUBLIC FUNCTIONS ***********************************************************/
136 KeQueryPerformanceCounter(
137 OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL
)
139 LARGE_INTEGER Result
;
141 /* Make sure it's calibrated */
142 ASSERT(HalpCpuClockFrequency
.QuadPart
!= 0);
144 /* Does the caller want the frequency? */
145 if (PerformanceFrequency
)
147 /* Return tsc frequency */
148 *PerformanceFrequency
= HalpCpuClockFrequency
;
151 /* Return the current value */
152 Result
.QuadPart
= __rdtsc();
158 KeStallExecutionProcessor(ULONG MicroSeconds
)
160 ULONG64 StartTime
, EndTime
;
162 /* Get the initial time */
163 StartTime
= __rdtsc();
165 /* Calculate the ending time */
166 EndTime
= StartTime
+ KeGetPcr()->StallScaleFactor
* MicroSeconds
;
168 /* Loop until time is elapsed */
169 while (__rdtsc() < EndTime
);
174 HalCalibratePerformanceCounter(
175 IN
volatile PLONG Count
,
176 IN ULONGLONG NewCount
)