ReactOS  0.4.15-dev-5618-g8866b9d
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 #define NDEBUG
17 #include <debug.h>
18 
19 /* GLOBALS ********************************************************************/
20 
21 static const UCHAR RtcMinimumClockRate = 6; /* Minimum rate 6: 1024 Hz / 0.97 ms */
22 static const UCHAR RtcMaximumClockRate = 10; /* Maximum rate 10: 64 Hz / 15.6 ms */
23 static UCHAR HalpCurrentClockRate = 10; /* Initial rate 10: 64 Hz / 15.6 ms */
31 
56 ULONG
58 {
59  /* Calculate frequency */
60  ULONG Frequency = 32768 >> (Rate - 1);
61 
62  /* Calculate interval in 0.1ns interval: Interval = (1 / Frequency) * 10,000,000,000 */
63  return 10000000000ULL / Frequency;
64 }
65 
66 VOID
68 {
69  UCHAR RegisterA;
70  ULONG PreciseIncrement;
71 
72  /* Update the global values */
73  HalpCurrentClockRate = ClockRate;
74  PreciseIncrement = RtcClockRateToPreciseIncrement(ClockRate);
75  HalpCurrentTimeIncrement = PreciseIncrement / 1000;
76  HalpCurrentFractionalIncrement = PreciseIncrement % 1000;
77 
78  /* Acquire CMOS lock */
80 
81  // TODO: disable NMI
82 
83  /* Read value of register A */
84  RegisterA = HalpReadCmos(RTC_REGISTER_A);
85 
86  /* Change lower 4 bits to new rate */
87  RegisterA &= 0xF0;
88  RegisterA |= ClockRate;
89 
90  /* Write the new value */
91  HalpWriteCmos(RTC_REGISTER_A, RegisterA);
92 
93  /* Release CMOS lock */
95 }
96 
97 CODE_SEG("INIT")
98 VOID
99 NTAPI
101 {
102  ULONG_PTR EFlags;
103  UCHAR RegisterB;
104 
105  /* Save EFlags and disable interrupts */
106  EFlags = __readeflags();
107  _disable();
108 
109  // TODO: disable NMI
110 
111  /* Acquire CMOS lock */
113 
114  /* Enable the periodic interrupt in the CMOS */
115  RegisterB = HalpReadCmos(RTC_REGISTER_B);
117 
118  /* Release CMOS lock */
120 
121  /* Set initial rate */
123 
124  /* Restore interrupt state */
125  __writeeflags(EFlags);
126 
127  /* Calculate minumum and maximum increment */
130 
131  /* Notify the kernel about the maximum and minimum increment */
133 
134  /* Enable the timer interrupt */
136 
137  DPRINT1("Clock initialized\n");
138 }
139 
140 VOID
141 FASTCALL
143 {
144  ULONG LastIncrement;
145  KIRQL Irql;
146 
147  /* Enter trap */
148  KiEnterInterruptTrap(TrapFrame);
149 #ifdef _M_AMD64
150  /* This is for debugging */
151  TrapFrame->ErrorCode = 0xc10c4;
152 #endif
153 
154  /* Start the interrupt */
156  {
157  /* Spurious, just end the interrupt */
158  KiEoiHelper(TrapFrame);
159  }
160 
161  /* Read register C, so that the next interrupt can happen */
163 
164  /* Save increment */
165  LastIncrement = HalpCurrentTimeIncrement;
166 
167  /* Check if the running fraction has accounted for 100 ns */
169  if (HalpRunningFraction >= 1000)
170  {
171  LastIncrement++;
172  HalpRunningFraction -= 1000;
173  }
174 
175  /* Check if someone changed the time rate */
176  if (HalpSetClockRate)
177  {
178  /* Set new clock rate */
180 
181  /* We're done */
183  }
184 
185  /* Update the system time -- on x86 the kernel will exit this trap */
186  KeUpdateSystemTime(TrapFrame, LastIncrement, Irql);
187 }
188 
189 ULONG
190 NTAPI
192 {
193  UCHAR Rate;
194  ULONG CurrentIncrement;
195 
196  /* Lookup largest value below given Increment */
197  for (Rate = RtcMinimumClockRate; Rate <= RtcMaximumClockRate; Rate++)
198  {
199  /* Check if this is the largest rate possible */
200  CurrentIncrement = RtcClockRateToPreciseIncrement(Rate + 1) / 1000;
201  if (Increment > CurrentIncrement) break;
202  }
203 
204  /* Set the rate and tell HAL we want to change it */
205  HalpNextClockRate = Rate;
207 
208  /* Return the real increment */
209  return RtcClockRateToPreciseIncrement(Rate) / 1000;
210 }
static ULONG HalpRunningFraction
Definition: rtctimer.c:28
#define IN
Definition: typedefs.h:39
VOID NTAPI HalpWriteCmos(_In_ UCHAR Reg, _In_ UCHAR Value)
Definition: cmos.c:132
BOOLEAN NTAPI HalEnableSystemInterrupt(IN ULONG Vector, IN KIRQL Irql, IN KINTERRUPT_MODE InterruptMode)
Definition: pic.c:295
VOID FASTCALL HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame)
Definition: rtctimer.c:142
VOID NTAPI KeSetTimeIncrement(IN ULONG MaxIncrement, IN ULONG MinIncrement)
Definition: ntoskrnl.c:28
#define TRUE
Definition: types.h:120
VOID FASTCALL KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame, IN ULONG Increment, IN KIRQL OldIrql)
Definition: time.c:64
BOOLEAN NTAPI HalBeginSystemInterrupt(IN KIRQL Irql, IN ULONG Vector, OUT PKIRQL OldIrql)
Definition: pic.c:321
VOID NTAPI HalpInitializeClock(VOID)
Definition: rtctimer.c:100
#define FASTCALL
Definition: nt_native.h:50
_Out_ PKIRQL Irql
Definition: csq.h:179
DECLSPEC_NORETURN VOID FASTCALL KiEoiHelper(IN PKTRAP_FRAME TrapFrame)
Definition: traphdlr.c:126
VOID RtcSetClockRate(UCHAR ClockRate)
Definition: rtctimer.c:67
static BOOLEAN HalpSetClockRate
Definition: rtctimer.c:29
uint32_t ULONG_PTR
Definition: typedefs.h:65
static const UCHAR RtcMaximumClockRate
Definition: rtctimer.c:22
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define RTC_REG_B_PI
Definition: halhw.h:16
static UCHAR HalpNextClockRate
Definition: rtctimer.c:30
__INTRIN_INLINE uintptr_t __readeflags(void)
Definition: intrin_x86.h:1674
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
VOID NTAPI HalpReleaseCmosSpinLock(VOID)
Definition: spinlock.c:243
unsigned char BOOLEAN
#define APIC_CLOCK_VECTOR
Definition: apicp.h:44
FORCEINLINE ULONG RtcClockRateToPreciseIncrement(UCHAR Rate)
Converts the CMOS RTC rate into the time increment in 100ns intervals.
Definition: rtctimer.c:57
#define ULL(a, b)
Definition: format_msg.c:27
ULONG NTAPI HalSetTimeIncrement(IN ULONG Increment)
Definition: rtctimer.c:191
static const UCHAR RtcMinimumClockRate
Definition: rtctimer.c:21
static UCHAR HalpCurrentClockRate
Definition: rtctimer.c:23
VOID NTAPI HalpAcquireCmosSpinLock(VOID)
Definition: spinlock.c:226
#define CLOCK_LEVEL
Definition: ketypes.h:16
unsigned char UCHAR
Definition: xmlstorage.h:181
__INTRIN_INLINE void __writeeflags(uintptr_t Value)
Definition: intrin_x86.h:1669
#define RTC_REGISTER_C
Definition: halhw.h:17
static ULONG HalpMaximumTimeIncrement
Definition: rtctimer.c:26
#define RTC_REGISTER_B
Definition: halhw.h:15
FORCEINLINE VOID KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame)
Definition: trap_x.h:368
#define FORCEINLINE
Definition: wdftypes.h:67
UCHAR NTAPI HalpReadCmos(_In_ UCHAR Reg)
Definition: cmos.c:123
#define RTC_REGISTER_A
Definition: xboxrtc.c:21
static LARGE_INTEGER Frequency
Definition: clock.c:41
#define DPRINT1
Definition: precomp.h:8
static ULONG HalpCurrentFractionalIncrement
Definition: rtctimer.c:27
static ULONG HalpCurrentTimeIncrement
Definition: rtctimer.c:24
void __cdecl _disable(void)
Definition: intrin_arm.h:365
unsigned int ULONG
Definition: retypes.h:1
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG Increment
Definition: CrNtStubs.h:42
static CODE_SEG("PAGE")
Definition: isapnp.c:1482
static ULONG HalpMinimumTimeIncrement
Definition: rtctimer.c:25