Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <hal.h>
00013 #define NDEBUG
00014 #include <debug.h>
00015
00016
00017
00018 #define PIT_LATCH 0x00
00019
00020 LARGE_INTEGER HalpLastPerfCounter;
00021 LARGE_INTEGER HalpPerfCounter;
00022 ULONG HalpPerfCounterCutoff;
00023 BOOLEAN HalpClockSetMSRate;
00024 ULONG HalpCurrentTimeIncrement;
00025 ULONG HalpCurrentRollOver;
00026 ULONG HalpNextMSRate = 14;
00027 ULONG HalpLargestClockMS = 15;
00028
00029 static struct _HALP_ROLLOVER
00030 {
00031 ULONG RollOver;
00032 ULONG Increment;
00033 } HalpRolloverTable[15] =
00034 {
00035 {1197, 10032},
00036 {2394, 20064},
00037 {3591, 30096},
00038 {4767, 39952},
00039 {5964, 49984},
00040 {7161, 60016},
00041 {8358, 70048},
00042 {9555, 80080},
00043 {10731, 89936},
00044 {11949, 100144},
00045 {13125, 110000},
00046 {14322, 120032},
00047 {15519, 130064},
00048 {16695, 139920},
00049 {17892, 149952}
00050 };
00051
00052
00053
00054 FORCEINLINE
00055 ULONG
00056 HalpRead8254Value(void)
00057 {
00058 ULONG TimerValue;
00059
00060
00061 __outbyte(TIMER_CONTROL_PORT, PIT_LATCH);
00062 __nop();
00063
00064
00065 TimerValue = __inbyte(TIMER_CHANNEL0_DATA_PORT);
00066 __nop();
00067 TimerValue |= __inbyte(TIMER_CHANNEL0_DATA_PORT) << 8;
00068
00069 return TimerValue;
00070 }
00071
00072 VOID
00073 NTAPI
00074 HalpSetTimerRollOver(USHORT RollOver)
00075 {
00076 ULONG_PTR Flags;
00077 TIMER_CONTROL_PORT_REGISTER TimerControl;
00078
00079
00080 Flags = __readeflags();
00081 _disable();
00082
00083
00084 TimerControl.BcdMode = FALSE;
00085
00086
00087
00088
00089
00090
00091
00092
00093 TimerControl.OperatingMode = PitOperatingMode2;
00094 TimerControl.Channel = PitChannel0;
00095
00096
00097 TimerControl.AccessMode = PitAccessModeLowHigh;
00098
00099
00100 __outbyte(TIMER_CONTROL_PORT, TimerControl.Bits);
00101
00102
00103 __outbyte(TIMER_CHANNEL0_DATA_PORT, RollOver & 0xFF);
00104 __outbyte(TIMER_CHANNEL0_DATA_PORT, RollOver >> 8);
00105
00106
00107 __writeeflags(Flags);
00108 }
00109
00110 VOID
00111 NTAPI
00112 INIT_FUNCTION
00113 HalpInitializeClock(VOID)
00114 {
00115 ULONG Increment;
00116 USHORT RollOver;
00117
00118 DPRINT("HalpInitializeClock()\n");
00119
00120
00121 Increment = HalpRolloverTable[HalpLargestClockMS - 1].Increment;
00122 RollOver = (USHORT)HalpRolloverTable[HalpLargestClockMS - 1].RollOver;
00123
00124
00125 KeSetTimeIncrement(Increment, HalpRolloverTable[0].Increment);
00126
00127
00128 HalpSetTimerRollOver(RollOver);
00129
00130
00131 HalpCurrentRollOver = RollOver;
00132 HalpCurrentTimeIncrement = Increment;
00133 }
00134
00135 #ifdef _M_IX86
00136 #ifndef _MINIHAL_
00137 VOID
00138 FASTCALL
00139 HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame)
00140 {
00141 ULONG LastIncrement;
00142 KIRQL Irql;
00143
00144
00145 KiEnterInterruptTrap(TrapFrame);
00146
00147
00148 if (HalBeginSystemInterrupt(CLOCK2_LEVEL, PRIMARY_VECTOR_BASE, &Irql))
00149 {
00150
00151 HalpPerfCounter.QuadPart += HalpCurrentRollOver;
00152 HalpPerfCounterCutoff = KiEnableTimerWatchdog;
00153
00154
00155 LastIncrement = HalpCurrentTimeIncrement;
00156
00157
00158 if (HalpClockSetMSRate)
00159 {
00160
00161 HalpCurrentTimeIncrement = HalpRolloverTable[HalpNextMSRate - 1].Increment;
00162 HalpCurrentRollOver = HalpRolloverTable[HalpNextMSRate - 1].RollOver;
00163
00164
00165 HalpSetTimerRollOver((USHORT)HalpCurrentRollOver);
00166
00167
00168 HalpClockSetMSRate = FALSE;
00169 }
00170
00171
00172 KeUpdateSystemTime(TrapFrame, LastIncrement, Irql);
00173 }
00174
00175
00176 KiEoiHelper(TrapFrame);
00177 }
00178
00179 VOID
00180 FASTCALL
00181 HalpProfileInterruptHandler(IN PKTRAP_FRAME TrapFrame)
00182 {
00183 KIRQL Irql;
00184
00185
00186 KiEnterInterruptTrap(TrapFrame);
00187
00188
00189 if (HalBeginSystemInterrupt(PROFILE_LEVEL, PRIMARY_VECTOR_BASE + 8, &Irql))
00190 {
00191
00192 UNIMPLEMENTED;
00193 ASSERT(FALSE);
00194 }
00195
00196
00197 KiEoiHelper(TrapFrame);
00198 }
00199 #endif
00200
00201 #endif
00202
00203
00204
00205
00206
00207
00208 VOID
00209 NTAPI
00210 HalCalibratePerformanceCounter(IN volatile PLONG Count,
00211 IN ULONGLONG NewCount)
00212 {
00213 ULONG_PTR Flags;
00214
00215
00216 Flags = __readeflags();
00217 _disable();
00218
00219
00220 _InterlockedDecrement(Count);
00221
00222
00223 while (*Count);
00224
00225
00226 __writeeflags(Flags);
00227 }
00228
00229
00230
00231
00232 ULONG
00233 NTAPI
00234 HalSetTimeIncrement(IN ULONG Increment)
00235 {
00236
00237 Increment /= 10000;
00238
00239
00240 if (Increment > HalpLargestClockMS) Increment = HalpLargestClockMS;
00241 if (Increment <= 0) Increment = 1;
00242
00243
00244 HalpNextMSRate = Increment;
00245 HalpClockSetMSRate = TRUE;
00246
00247
00248 return HalpRolloverTable[Increment - 1].Increment;
00249 }
00250
00251 LARGE_INTEGER
00252 NTAPI
00253 KeQueryPerformanceCounter(PLARGE_INTEGER PerformanceFrequency)
00254 {
00255 LARGE_INTEGER CurrentPerfCounter;
00256 ULONG CounterValue, ClockDelta;
00257 KIRQL OldIrql;
00258
00259
00260 if (PerformanceFrequency) PerformanceFrequency->QuadPart = PIT_FREQUENCY;
00261
00262
00263 if (HalpCurrentRollOver == 0) return HalpPerfCounter;
00264
00265
00266 if(!(__readeflags() & EFLAGS_INTERRUPT_MASK)) return HalpPerfCounter;
00267
00268
00269 OldIrql = KeGetCurrentIrql();
00270 if (OldIrql < DISPATCH_LEVEL) KfRaiseIrql(DISPATCH_LEVEL);
00271
00272 do
00273 {
00274
00275 CurrentPerfCounter = HalpPerfCounter;
00276
00277
00278 CounterValue = HalpRead8254Value();
00279
00280
00281 } while (CurrentPerfCounter.QuadPart != HalpPerfCounter.QuadPart);
00282
00283
00284
00285
00286 if (CounterValue > HalpCurrentRollOver) CounterValue = HalpCurrentRollOver;
00287
00288
00289
00290
00291 ClockDelta = HalpCurrentRollOver - CounterValue;
00292
00293
00294 CurrentPerfCounter.QuadPart += ClockDelta;
00295
00296
00297
00298
00299 if (CurrentPerfCounter.QuadPart < HalpLastPerfCounter.QuadPart)
00300 {
00301
00302 CurrentPerfCounter.QuadPart += HalpCurrentRollOver;
00303 }
00304
00305
00306 HalpLastPerfCounter = CurrentPerfCounter;
00307
00308
00309 if (OldIrql < DISPATCH_LEVEL) KfLowerIrql(OldIrql);
00310
00311
00312 return CurrentPerfCounter;
00313 }
00314
00315