ReactOS 0.4.15-dev-7934-g1dc8d80
timer.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PURPOSE: HAL Timer Routines
5 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
6 * Timo Kreuzer (timo.kreuzer@reactos.org)
7 */
8
9/* INCLUDES ******************************************************************/
10
11#include <hal.h>
12
13#define NDEBUG
14#include <debug.h>
15
16/* GLOBALS *******************************************************************/
17
18#define PIT_LATCH 0x00
19
21
30
31/* PRIVATE FUNCTIONS *********************************************************/
32
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}
50
51VOID
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}
88
89CODE_SEG("INIT")
90VOID
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}
117
118#ifdef _M_IX86
119#ifndef _MINIHAL_
120VOID
123{
124 ULONG LastIncrement;
125 KIRQL Irql;
126
127 /* Enter trap */
128 KiEnterInterruptTrap(TrapFrame);
129
130 /* Start the interrupt */
132 {
133 /* Update the performance counter */
136
137 /* Save increment */
138 LastIncrement = HalpCurrentTimeIncrement;
139
140 /* Check if someone changed the time rate */
142 {
143 /* Update the global values */
146
147 /* Set new timer rollover */
149
150 /* We're done */
152 }
153
154 /* Update the system time -- the kernel will exit this trap */
155 KeUpdateSystemTime(TrapFrame, LastIncrement, Irql);
156 }
157
158 /* Spurious, just end the interrupt */
159 KiEoiHelper(TrapFrame);
160}
161
162VOID
165{
166 KIRQL Irql;
167
168 /* Enter trap */
169 KiEnterInterruptTrap(TrapFrame);
170
171 /* Start the interrupt */
173 {
174#if defined(SARCH_PC98)
175 /* Clear the interrupt flag */
179#else
180 /* Spin until the interrupt pending bit is clear */
183 NOTHING;
185#endif
186
187 /* If profiling is enabled, call the kernel function */
189 {
190 KeProfileInterrupt(TrapFrame);
191 }
192
193 /* Finish the interrupt */
194 _disable();
195 HalEndSystemInterrupt(Irql, TrapFrame);
196 }
197
198 /* Spurious, just end the interrupt */
199 KiEoiHelper(TrapFrame);
200}
201#endif /* !_MINIHAL_ */
202
203#endif /* _M_IX86 */
204
205/* PUBLIC FUNCTIONS ***********************************************************/
206
207/*
208 * @implemented
209 */
210VOID
211NTAPI
213 IN ULONGLONG NewCount)
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}
230
231/*
232 * @implemented
233 */
234ULONG
235NTAPI
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}
252
254NTAPI
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}
316
317/* EOF */
#define CODE_SEG(...)
unsigned char BOOLEAN
#define EFLAGS_INTERRUPT_MASK
Definition: SystemCall.c:11
#define VOID
Definition: acefi.h:82
VOID FASTCALL HalpProfileInterruptHandler(_In_ PKTRAP_FRAME TrapFrame)
Definition: apictimer.c:66
VOID NTAPI KeSetTimeIncrement(IN ULONG MaxIncrement, IN ULONG MinIncrement)
Definition: ntoskrnl.c:28
_Out_ PKIRQL Irql
Definition: csq.h:179
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define CLOCK2_LEVEL
Definition: env_spec_w32.h:700
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define PROFILE_LEVEL
Definition: env_spec_w32.h:698
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG Increment
Definition: CrNtStubs.h:46
VOID NTAPI HalEndSystemInterrupt(IN KIRQL OldIrql, IN PKTRAP_FRAME TrapFrame)
Definition: pic.c:335
BOOLEAN NTAPI HalBeginSystemInterrupt(IN KIRQL Irql, IN ULONG Vector, OUT PKIRQL OldIrql)
Definition: pic.c:321
VOID FASTCALL KfLowerIrql(IN KIRQL NewIrql)
Definition: pic.c:232
KIRQL FASTCALL KfRaiseIrql(IN KIRQL NewIrql)
Definition: pic.c:187
VOID FASTCALL KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame, IN ULONG Increment, IN KIRQL OldIrql)
Definition: time.c:64
ULONG NTAPI HalSetTimeIncrement(IN ULONG Increment)
Definition: timer.c:102
LARGE_INTEGER NTAPI KeQueryPerformanceCounter(IN PLARGE_INTEGER PerformanceFreq)
Definition: timer.c:138
VOID HalpInitializeClock(VOID)
Definition: timer.c:54
ULONG HalpCurrentTimeIncrement
Definition: timer.c:25
VOID NTAPI HalCalibratePerformanceCounter(IN volatile PLONG Count, IN ULONGLONG NewCount)
Definition: timer.c:90
VOID NTAPI HalpReleaseCmosSpinLock(VOID)
Definition: spinlock.c:243
VOID NTAPI HalpAcquireCmosSpinLock(VOID)
Definition: spinlock.c:226
LARGE_INTEGER HalpLastPerfCounter
Definition: timer.c:22
BOOLEAN HalpClockSetMSRate
Definition: timer.c:25
ULONG HalpLargestClockMS
Definition: timer.c:29
ULONG HalpCurrentRollOver
Definition: timer.c:27
ULONG HalpPerfCounterCutoff
Definition: timer.c:24
FORCEINLINE ULONG HalpRead8254Value(void)
Definition: timer.c:35
#define PIT_LATCH
Definition: timer.c:18
ULONG HalpNextMSRate
Definition: timer.c:28
VOID NTAPI HalpSetTimerRollOver(USHORT RollOver)
Definition: timer.c:53
HALP_ROLLOVER HalpRolloverTable[15]
Definition: clock.c:15
LARGE_INTEGER HalpPerfCounter
Definition: timer.c:23
VOID NTAPI HalpInitializeClockPc98(VOID)
Definition: clock.c:62
UCHAR NTAPI HalpReadCmos(_In_ UCHAR Reg)
Definition: cmos.c:123
#define PRIMARY_VECTOR_BASE
Definition: halp.h:16
#define PIT_FREQUENCY
Definition: halhw.h:61
@ PitChannel0
Definition: halhw.h:102
#define PIC_RTC_IRQ
Definition: halhw.h:157
#define TIMER_CONTROL_PORT
Definition: halhw.h:70
@ PitAccessModeLowHigh
Definition: halhw.h:97
#define RTC_REG_C_IRQ
Definition: halhw.h:18
#define PIC_TIMER_IRQ
Definition: halhw.h:155
#define RTC_REGISTER_C
Definition: halhw.h:17
@ PitOperatingMode2
Definition: halhw.h:84
#define TIMER_CHANNEL0_DATA_PORT
Definition: halhw.h:67
BOOLEAN HalpProfilingStopped
Definition: profil.c:18
#define NOTHING
Definition: input_list.c:10
void __cdecl _disable(void)
Definition: intrin_arm.h:365
void __nop(void)
Definition: intrin_x86.h:2042
long __cdecl _InterlockedDecrement(_Interlocked_operand_ long volatile *_Addend)
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
__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
#define FASTCALL
Definition: nt_native.h:50
DECLSPEC_NORETURN VOID FASTCALL KiEoiHelper(IN PKTRAP_FRAME TrapFrame)
Definition: traphdlr.c:126
unsigned short USHORT
Definition: pedump.c:61
VOID NTAPI KeProfileInterrupt(IN PKTRAP_FRAME TrapFrame)
Definition: profobj.c:296
#define RTC_IO_i_INTERRUPT_RESET
Definition: rtc.h:44
VOID FASTCALL HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame)
Definition: rtctimer.c:143
#define DPRINT
Definition: sndvol32.h:71
ULONG Increment
Definition: halp.h:244
ULONG RollOver
Definition: halp.h:243
BOOLEAN KiEnableTimerWatchdog
Definition: timerobj.c:20
FORCEINLINE VOID KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame)
Definition: trap_x.h:368
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
int32_t * PLONG
Definition: typedefs.h:58
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
LONGLONG QuadPart
Definition: typedefs.h:114
#define FORCEINLINE
Definition: wdftypes.h:67
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778