ReactOS 0.4.15-dev-7842-g558ab78
rtctimer.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GNU GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/apic/rtctimer.c
5 * PURPOSE: HAL APIC Management and Control Code
6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
7 * REFERENCES: https://wiki.osdev.org/RTC
8 * https://forum.osdev.org/viewtopic.php?f=13&t=20825&start=0
9 * http://www.bioscentral.com/misc/cmosmap.htm
10 */
11
12/* INCLUDES *******************************************************************/
13
14#include <hal.h>
15#include "apicp.h"
16#include <smp.h>
17#define NDEBUG
18#include <debug.h>
19
20/* GLOBALS ********************************************************************/
21
22static const UCHAR RtcMinimumClockRate = 6; /* Minimum rate 6: 1024 Hz / 0.97 ms */
23static const UCHAR RtcMaximumClockRate = 10; /* Maximum rate 10: 64 Hz / 15.6 ms */
24static UCHAR HalpCurrentClockRate = 10; /* Initial rate 10: 64 Hz / 15.6 ms */
32
59{
60 /* Calculate frequency */
61 ULONG Frequency = 32768 >> (Rate - 1);
62
63 /* Calculate interval in 0.1ns interval: Interval = (1 / Frequency) * 10,000,000,000 */
64 return 10000000000ULL / Frequency;
65}
66
67VOID
69{
70 UCHAR RegisterA;
71 ULONG PreciseIncrement;
72
73 /* Update the global values */
74 HalpCurrentClockRate = ClockRate;
75 PreciseIncrement = RtcClockRateToPreciseIncrement(ClockRate);
76 HalpCurrentTimeIncrement = PreciseIncrement / 1000;
77 HalpCurrentFractionalIncrement = PreciseIncrement % 1000;
78
79 /* Acquire CMOS lock */
81
82 // TODO: disable NMI
83
84 /* Read value of register A */
85 RegisterA = HalpReadCmos(RTC_REGISTER_A);
86
87 /* Change lower 4 bits to new rate */
88 RegisterA &= 0xF0;
89 RegisterA |= ClockRate;
90
91 /* Write the new value */
92 HalpWriteCmos(RTC_REGISTER_A, RegisterA);
93
94 /* Release CMOS lock */
96}
97
98CODE_SEG("INIT")
99VOID
100NTAPI
102{
103 ULONG_PTR EFlags;
104 UCHAR RegisterB;
105
106 /* Save EFlags and disable interrupts */
107 EFlags = __readeflags();
108 _disable();
109
110 // TODO: disable NMI
111
112 /* Acquire CMOS lock */
114
115 /* Enable the periodic interrupt in the CMOS */
116 RegisterB = HalpReadCmos(RTC_REGISTER_B);
118
119 /* Release CMOS lock */
121
122 /* Set initial rate */
124
125 /* Restore interrupt state */
126 __writeeflags(EFlags);
127
128 /* Calculate minumum and maximum increment */
131
132 /* Notify the kernel about the maximum and minimum increment */
134
135 /* Enable the timer interrupt */
137
138 DPRINT1("Clock initialized\n");
139}
140
141VOID
144{
145 ULONG LastIncrement;
146 KIRQL Irql;
147
148 /* Enter trap */
149 KiEnterInterruptTrap(TrapFrame);
150#ifdef _M_AMD64
151 /* This is for debugging */
152 TrapFrame->ErrorCode = 0xc10c4;
153#endif
154
155 /* Start the interrupt */
157 {
158 /* Spurious, just end the interrupt */
159 KiEoiHelper(TrapFrame);
160 }
161
162 /* Read register C, so that the next interrupt can happen */
164
165 /* Save increment */
166 LastIncrement = HalpCurrentTimeIncrement;
167
168 /* Check if the running fraction has accounted for 100 ns */
170 if (HalpRunningFraction >= 1000)
171 {
172 LastIncrement++;
173 HalpRunningFraction -= 1000;
174 }
175
176 /* Check if someone changed the time rate */
178 {
179 /* Set new clock rate */
181
182 /* We're done */
184 }
185
186 /* Send the clock IPI to all other CPUs */
188
189 /* Update the system time -- on x86 the kernel will exit this trap */
190 KeUpdateSystemTime(TrapFrame, LastIncrement, Irql);
191}
192
193VOID
196{
197 KIRQL Irql;
198
199 /* Enter trap */
200 KiEnterInterruptTrap(TrapFrame);
201#ifdef _M_AMD64
202 /* This is for debugging */
203 TrapFrame->ErrorCode = 0xc10c4;
204#endif
205
206 /* Start the interrupt */
208 {
209 /* Spurious, just end the interrupt */
210 KiEoiHelper(TrapFrame);
211 }
212
213 /* Call the kernel to update runtimes */
214 KeUpdateRunTime(TrapFrame, Irql);
215
216 /* End the interrupt */
217 KiEndInterrupt(Irql, TrapFrame);
218}
219
220ULONG
221NTAPI
223{
224 UCHAR Rate;
225 ULONG CurrentIncrement;
226
227 /* Lookup largest value below given Increment */
228 for (Rate = RtcMinimumClockRate; Rate <= RtcMaximumClockRate; Rate++)
229 {
230 /* Check if this is the largest rate possible */
231 CurrentIncrement = RtcClockRateToPreciseIncrement(Rate + 1) / 1000;
232 if (Increment > CurrentIncrement) break;
233 }
234
235 /* Set the rate and tell HAL we want to change it */
236 HalpNextClockRate = Rate;
238
239 /* Return the real increment */
240 return RtcClockRateToPreciseIncrement(Rate) / 1000;
241}
unsigned char BOOLEAN
#define CLOCK_IPI_VECTOR
Definition: apicp.h:46
#define APIC_CLOCK_VECTOR
Definition: apicp.h:44
#define DPRINT1
Definition: precomp.h:8
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
UCHAR KIRQL
Definition: env_spec_w32.h:591
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG Increment
Definition: CrNtStubs.h:46
BOOLEAN NTAPI HalBeginSystemInterrupt(IN KIRQL Irql, IN ULONG Vector, OUT PKIRQL OldIrql)
Definition: pic.c:321
BOOLEAN NTAPI HalEnableSystemInterrupt(IN ULONG Vector, IN KIRQL Irql, IN KINTERRUPT_MODE InterruptMode)
Definition: pic.c:295
VOID FASTCALL KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame, IN ULONG Increment, IN KIRQL OldIrql)
Definition: time.c:64
VOID NTAPI HalpReleaseCmosSpinLock(VOID)
Definition: spinlock.c:243
VOID NTAPI HalpAcquireCmosSpinLock(VOID)
Definition: spinlock.c:226
VOID NTAPI HalpWriteCmos(_In_ UCHAR Reg, _In_ UCHAR Value)
Definition: cmos.c:132
UCHAR NTAPI HalpReadCmos(_In_ UCHAR Reg)
Definition: cmos.c:123
#define RTC_REG_B_PI
Definition: halhw.h:16
#define RTC_REGISTER_B
Definition: halhw.h:15
#define RTC_REGISTER_C
Definition: halhw.h:17
VOID NTAPI KeUpdateRunTime(_In_ PKTRAP_FRAME TrapFrame, _In_ KIRQL Irql)
void __cdecl _disable(void)
Definition: intrin_arm.h:365
__INTRIN_INLINE void __writeeflags(uintptr_t Value)
Definition: intrin_x86.h:1669
__INTRIN_INLINE uintptr_t __readeflags(void)
Definition: intrin_x86.h:1674
static CODE_SEG("PAGE")
Definition: isapnp.c:1482
#define CLOCK_LEVEL
Definition: ketypes.h:16
#define FASTCALL
Definition: nt_native.h:50
#define KiEndInterrupt(x, y)
Definition: ke.h:175
DECLSPEC_NORETURN VOID FASTCALL KiEoiHelper(IN PKTRAP_FRAME TrapFrame)
Definition: traphdlr.c:126
VOID FASTCALL HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame)
Definition: rtctimer.c:143
static UCHAR HalpCurrentClockRate
Definition: rtctimer.c:24
ULONG NTAPI HalSetTimeIncrement(IN ULONG Increment)
Definition: rtctimer.c:222
static BOOLEAN HalpSetClockRate
Definition: rtctimer.c:30
static const UCHAR RtcMinimumClockRate
Definition: rtctimer.c:22
VOID FASTCALL HalpClockIpiHandler(IN PKTRAP_FRAME TrapFrame)
Definition: rtctimer.c:195
static ULONG HalpCurrentFractionalIncrement
Definition: rtctimer.c:28
static const UCHAR RtcMaximumClockRate
Definition: rtctimer.c:23
static UCHAR HalpNextClockRate
Definition: rtctimer.c:31
static ULONG HalpCurrentTimeIncrement
Definition: rtctimer.c:25
static ULONG HalpRunningFraction
Definition: rtctimer.c:29
VOID RtcSetClockRate(UCHAR ClockRate)
Definition: rtctimer.c:68
FORCEINLINE ULONG RtcClockRateToPreciseIncrement(UCHAR Rate)
Converts the CMOS RTC rate into the time increment in 100ns intervals.
Definition: rtctimer.c:58
VOID NTAPI HalpInitializeClock(VOID)
Definition: rtctimer.c:101
static ULONG HalpMinimumTimeIncrement
Definition: rtctimer.c:26
static ULONG HalpMaximumTimeIncrement
Definition: rtctimer.c:27
@ Latched
Definition: miniport.h:81
static LARGE_INTEGER Frequency
Definition: clock.c:41
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
uint32_t ULONG
Definition: typedefs.h:59
VOID FASTCALL HalpBroadcastClockIpi(_In_ UCHAR Vector)
Definition: up.c:45
#define FORCEINLINE
Definition: wdftypes.h:67
#define RTC_REGISTER_A
Definition: xboxrtc.c:21
unsigned char UCHAR
Definition: xmlstorage.h:181