ReactOS 0.4.15-dev-7842-g558ab78
timer.c File Reference
#include <hal.h>
#include <debug.h>
Include dependency graph for timer.c:

Go to the source code of this file.

Macros

#define NDEBUG
 
#define PIT_LATCH   0x00
 

Functions

FORCEINLINE ULONG HalpRead8254Value (void)
 
VOID NTAPI HalpSetTimerRollOver (USHORT RollOver)
 
VOID NTAPI HalpInitializeClock (VOID)
 
VOID NTAPI HalCalibratePerformanceCounter (IN volatile PLONG Count, IN ULONGLONG NewCount)
 
ULONG NTAPI HalSetTimeIncrement (IN ULONG Increment)
 
LARGE_INTEGER NTAPI KeQueryPerformanceCounter (PLARGE_INTEGER PerformanceFrequency)
 

Variables

HALP_ROLLOVER HalpRolloverTable [15]
 
LARGE_INTEGER HalpLastPerfCounter
 
LARGE_INTEGER HalpPerfCounter
 
ULONG HalpPerfCounterCutoff
 
BOOLEAN HalpClockSetMSRate
 
ULONG HalpCurrentTimeIncrement
 
ULONG HalpCurrentRollOver
 
ULONG HalpNextMSRate = 14
 
ULONG HalpLargestClockMS = 15
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 13 of file timer.c.

◆ PIT_LATCH

#define PIT_LATCH   0x00

Definition at line 18 of file timer.c.

Function Documentation

◆ HalCalibratePerformanceCounter()

VOID NTAPI HalCalibratePerformanceCounter ( IN volatile PLONG  Count,
IN ULONGLONG  NewCount 
)

Definition at line 212 of file timer.c.

214{
216
217 /* Disable interrupts */
219 _disable();
220
221 /* Do a decrement for this CPU */
223
224 /* Wait for other CPUs */
225 while (*Count);
226
227 /* Restore interrupts if they were previously enabled */
229}
void __cdecl _disable(void)
Definition: intrin_arm.h:365
long __cdecl _InterlockedDecrement(_Interlocked_operand_ long volatile *_Addend)
__INTRIN_INLINE void __writeeflags(uintptr_t Value)
Definition: intrin_x86.h:1669
__INTRIN_INLINE uintptr_t __readeflags(void)
Definition: intrin_x86.h:1674
int Count
Definition: noreturn.cpp:7
uint32_t ULONG_PTR
Definition: typedefs.h:65
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170

◆ HalpInitializeClock()

VOID NTAPI HalpInitializeClock ( VOID  )

Definition at line 92 of file timer.c.

93{
95 USHORT RollOver;
96
97 DPRINT("HalpInitializeClock()\n");
98
99#if defined(SARCH_PC98)
101#endif
102
103 /* Get increment and rollover for the largest time clock ms possible */
105 RollOver = (USHORT)HalpRolloverTable[HalpLargestClockMS - 1].RollOver;
106
107 /* Set the maximum and minimum increment with the kernel */
109
110 /* Set the rollover value for the timer */
111 HalpSetTimerRollOver(RollOver);
112
113 /* Save rollover and increment */
114 HalpCurrentRollOver = RollOver;
116}
VOID NTAPI KeSetTimeIncrement(IN ULONG MaxIncrement, IN ULONG MinIncrement)
Definition: ntoskrnl.c:28
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG Increment
Definition: CrNtStubs.h:46
ULONG HalpCurrentTimeIncrement
Definition: timer.c:25
ULONG HalpLargestClockMS
Definition: timer.c:29
ULONG HalpCurrentRollOver
Definition: timer.c:27
VOID NTAPI HalpSetTimerRollOver(USHORT RollOver)
Definition: timer.c:53
HALP_ROLLOVER HalpRolloverTable[15]
Definition: clock.c:15
VOID NTAPI HalpInitializeClockPc98(VOID)
Definition: clock.c:62
unsigned short USHORT
Definition: pedump.c:61
#define DPRINT
Definition: sndvol32.h:71
ULONG Increment
Definition: halp.h:244
uint32_t ULONG
Definition: typedefs.h:59

◆ HalpRead8254Value()

FORCEINLINE ULONG HalpRead8254Value ( void  )

Definition at line 35 of file timer.c.

36{
37 ULONG TimerValue;
38
39 /* Send counter latch command for channel 0 */
41 __nop();
42
43 /* Read the value, LSB first */
45 __nop();
46 TimerValue |= __inbyte(TIMER_CHANNEL0_DATA_PORT) << 8;
47
48 return TimerValue;
49}
#define PIT_LATCH
Definition: timer.c:18
#define TIMER_CONTROL_PORT
Definition: halhw.h:70
#define TIMER_CHANNEL0_DATA_PORT
Definition: halhw.h:67
void __nop(void)
Definition: intrin_x86.h:2042
PPC_QUAL unsigned char __inbyte(const unsigned long Port)
Definition: intrin_ppc.h:539
PPC_QUAL void __outbyte(unsigned long const Port, const unsigned char Data)
Definition: intrin_ppc.h:605

Referenced by KeQueryPerformanceCounter().

◆ HalpSetTimerRollOver()

VOID NTAPI HalpSetTimerRollOver ( USHORT  RollOver)

Definition at line 53 of file timer.c.

54{
56 TIMER_CONTROL_PORT_REGISTER TimerControl;
57
58 /* Disable interrupts */
60 _disable();
61
62 /* Program the PIT for binary mode */
63 TimerControl.BcdMode = FALSE;
64
65 /*
66 * Program the PIT to generate a normal rate wave (Mode 2) on channel 0.
67 * Channel 0 is used for the IRQ0 clock interval timer, and channel
68 * 1 is used for DRAM refresh.
69 *
70 * Mode 2 gives much better accuracy than Mode 3.
71 */
72 TimerControl.OperatingMode = PitOperatingMode2;
73 TimerControl.Channel = PitChannel0;
74
75 /* Set the access mode that we'll use to program the reload value */
76 TimerControl.AccessMode = PitAccessModeLowHigh;
77
78 /* Now write the programming bits */
79 __outbyte(TIMER_CONTROL_PORT, TimerControl.Bits);
80
81 /* Next we write the reload value for channel 0 */
82 __outbyte(TIMER_CHANNEL0_DATA_PORT, RollOver & 0xFF);
83 __outbyte(TIMER_CHANNEL0_DATA_PORT, RollOver >> 8);
84
85 /* Restore interrupts if they were previously enabled */
87}
#define FALSE
Definition: types.h:117
@ PitChannel0
Definition: halhw.h:102
@ PitAccessModeLowHigh
Definition: halhw.h:97
@ PitOperatingMode2
Definition: halhw.h:84

Referenced by HalpInitializeClock().

◆ HalSetTimeIncrement()

ULONG NTAPI HalSetTimeIncrement ( IN ULONG  Increment)

Definition at line 236 of file timer.c.

237{
238 /* Round increment to ms */
239 Increment /= 10000;
240
241 /* Normalize between our minimum (1 ms) and maximum (variable) setting */
243 if (Increment <= 0) Increment = 1;
244
245 /* Set the rate and tell HAL we want to change it */
248
249 /* Return the increment */
251}
#define TRUE
Definition: types.h:120
BOOLEAN HalpClockSetMSRate
Definition: timer.c:25
ULONG HalpNextMSRate
Definition: timer.c:28

◆ KeQueryPerformanceCounter()

LARGE_INTEGER NTAPI KeQueryPerformanceCounter ( PLARGE_INTEGER PerformanceFrequency  )

Definition at line 255 of file timer.c.

256{
257 LARGE_INTEGER CurrentPerfCounter;
258 ULONG CounterValue, ClockDelta;
260
261 /* If caller wants performance frequency, return hardcoded value */
262 if (PerformanceFrequency) PerformanceFrequency->QuadPart = PIT_FREQUENCY;
263
264 /* Check if we were called too early */
265 if (HalpCurrentRollOver == 0) return HalpPerfCounter;
266
267 /* Check if interrupts are disabled */
269
270 /* Raise irql to DISPATCH_LEVEL */
273
274 do
275 {
276 /* Get the current performance counter value */
277 CurrentPerfCounter = HalpPerfCounter;
278
279 /* Read the 8254 counter value */
280 CounterValue = HalpRead8254Value();
281
282 /* Repeat if the value has changed (a clock interrupt happened) */
283 } while (CurrentPerfCounter.QuadPart != HalpPerfCounter.QuadPart);
284
285 /* After someone changed the clock rate, during the first clock cycle we
286 might see a counter value larger than the rollover. In this case we
287 pretend it already has the new rollover value. */
288 if (CounterValue > HalpCurrentRollOver) CounterValue = HalpCurrentRollOver;
289
290 /* The interrupt is issued on the falling edge of the OUT line, when the
291 counter changes from 1 to max. Calculate a clock delta, so that directly
292 after the interrupt it is 0, going up to (HalpCurrentRollOver - 1). */
293 ClockDelta = HalpCurrentRollOver - CounterValue;
294
295 /* Add the clock delta */
296 CurrentPerfCounter.QuadPart += ClockDelta;
297
298 /* Check if the value is smaller then before, this means, we somehow
299 missed an interrupt. This is a sign that the timer interrupt
300 is very inaccurate. Probably a virtual machine. */
301 if (CurrentPerfCounter.QuadPart < HalpLastPerfCounter.QuadPart)
302 {
303 /* We missed an interrupt. Assume we will receive it later */
304 CurrentPerfCounter.QuadPart += HalpCurrentRollOver;
305 }
306
307 /* Update the last counter value */
308 HalpLastPerfCounter = CurrentPerfCounter;
309
310 /* Restore previous irql */
312
313 /* Return the result */
314 return CurrentPerfCounter;
315}
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
VOID FASTCALL KfLowerIrql(IN KIRQL NewIrql)
Definition: pic.c:232
KIRQL FASTCALL KfRaiseIrql(IN KIRQL NewIrql)
Definition: pic.c:187
LARGE_INTEGER HalpLastPerfCounter
Definition: timer.c:22
FORCEINLINE ULONG HalpRead8254Value(void)
Definition: timer.c:35
LARGE_INTEGER HalpPerfCounter
Definition: timer.c:23
#define PIT_FREQUENCY
Definition: halhw.h:61
#define EFLAGS_INTERRUPT_MASK
Definition: ketypes.h:187
LONGLONG QuadPart
Definition: typedefs.h:114
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778

Variable Documentation

◆ HalpClockSetMSRate

BOOLEAN HalpClockSetMSRate

Definition at line 25 of file timer.c.

Referenced by HalSetTimeIncrement().

◆ HalpCurrentRollOver

ULONG HalpCurrentRollOver

Definition at line 27 of file timer.c.

Referenced by HalpInitializeClock(), and KeQueryPerformanceCounter().

◆ HalpCurrentTimeIncrement

ULONG HalpCurrentTimeIncrement

Definition at line 26 of file timer.c.

◆ HalpLargestClockMS

ULONG HalpLargestClockMS = 15

Definition at line 29 of file timer.c.

Referenced by HalpInitializeClock(), and HalSetTimeIncrement().

◆ HalpLastPerfCounter

LARGE_INTEGER HalpLastPerfCounter

Definition at line 22 of file timer.c.

Referenced by KeQueryPerformanceCounter().

◆ HalpNextMSRate

ULONG HalpNextMSRate = 14

Definition at line 28 of file timer.c.

Referenced by HalSetTimeIncrement().

◆ HalpPerfCounter

LARGE_INTEGER HalpPerfCounter

Definition at line 23 of file timer.c.

Referenced by KeQueryPerformanceCounter().

◆ HalpPerfCounterCutoff

ULONG HalpPerfCounterCutoff

Definition at line 24 of file timer.c.

◆ HalpRolloverTable

HALP_ROLLOVER HalpRolloverTable[15]
extern

Definition at line 15 of file clock.c.

Referenced by HalpInitializeClock(), HalpInitializeClockPc98(), and HalSetTimeIncrement().