diff --git a/reactos/hal/halx86/apic/apic.c b/reactos/hal/halx86/apic/apic.c index d613c5f94d4..7b151be49ff 100644 --- a/reactos/hal/halx86/apic/apic.c +++ b/reactos/hal/halx86/apic/apic.c @@ -113,6 +113,11 @@ KIRQL FORCEINLINE ApicGetCurrentIrql(VOID) { + // HACK: This won't work with amd64, where cr8 is modified directly, but + // VBox is broken and returns a wrong value when using a vmmcall after a + // page table modification. + return KeGetPcr()->Irql; + /* Read the TPR and convert it to an IRQL */ return TprToIrql(ApicRead(APIC_TPR)); } @@ -123,6 +128,9 @@ ApicSetCurrentIrql(KIRQL Irql) { /* Convert IRQL and write the TPR */ ApicWrite(APIC_TPR, IrqlToTpr(Irql)); + + /* HACK: Keep PCR field in sync, s.a. */ + KeGetPcr()->Irql = Irql; } UCHAR diff --git a/reactos/hal/halx86/apic/rtctimer.c b/reactos/hal/halx86/apic/rtctimer.c index dc487bd239a..31296530590 100644 --- a/reactos/hal/halx86/apic/rtctimer.c +++ b/reactos/hal/halx86/apic/rtctimer.c @@ -19,9 +19,10 @@ const UCHAR HalpClockVector = 0xD1; BOOLEAN HalpClockSetMSRate; UCHAR HalpNextMSRate; -UCHAR HalpCurrentRate = 9; +UCHAR HalpCurrentRate = 9; /* Initial rate 9: 128 Hz / 7,8 ms */ ULONG HalpCurrentTimeIncrement; -static UCHAR RtcLargestClockRate = 10; +static UCHAR RtcMinimumClockRate = 6; /* Minimum rate 6: 16 Hz / 62,5 ms */ +static UCHAR RtcMaximumClockRate = 10; /* Maximum rate 10: 256 Hz / 3,9 ms */ ULONG @@ -42,6 +43,10 @@ RtcSetClockRate(UCHAR ClockRate) EFlags = __readeflags(); _disable(); + /* Update the global values */ + HalpCurrentRate = ClockRate; + HalpCurrentTimeIncrement = RtcClockRateToIncrement(ClockRate); + /* Acquire CMOS lock */ HalpAcquireCmosSpinLock(); @@ -83,8 +88,13 @@ HalpInitializeClock(VOID) /* Release CMOS lock */ HalpReleaseCmosSpinLock(); + /* Set initial rate */ RtcSetClockRate(HalpCurrentRate); + /* Notify the kernel about the maximum and minimum increment */ + KeSetTimeIncrement(RtcClockRateToIncrement(RtcMaximumClockRate), + RtcClockRateToIncrement(RtcMinimumClockRate)); + DPRINT1("Clock initialized\n"); } @@ -110,10 +120,6 @@ HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame) /* Check if someone changed the time rate */ if (HalpClockSetMSRate) { - /* Update the global values */ - HalpCurrentRate = HalpNextMSRate; - HalpCurrentTimeIncrement = RtcClockRateToIncrement(HalpCurrentRate); - /* Set new clock rate */ RtcSetClockRate(HalpCurrentRate); @@ -143,7 +149,7 @@ HalSetTimeIncrement(IN ULONG Increment) UCHAR Rate; /* Lookup largest value below given Increment */ - for (Rate = 2; Rate < RtcLargestClockRate; Rate++) + for (Rate = RtcMinimumClockRate; Rate <= RtcMaximumClockRate; Rate++) { /* Check if this is the largest rate possible */ if (RtcClockRateToIncrement(Rate + 1) > Increment) break; diff --git a/reactos/hal/halx86/apic/tsc.c b/reactos/hal/halx86/apic/tsc.c index a551b9c3e4a..24b037dbcd6 100644 --- a/reactos/hal/halx86/apic/tsc.c +++ b/reactos/hal/halx86/apic/tsc.c @@ -17,11 +17,40 @@ LARGE_INTEGER HalpCpuClockFrequency = {INITIAL_STALL_COUNT * 1000000}; UCHAR TscCalibrationPhase; -LARGE_INTEGER TscCalibrationArray[NUM_SAMPLES]; +ULONG64 TscCalibrationArray[NUM_SAMPLES]; UCHAR HalpRtcClockVector = 0xD1; +#define RTC_MODE 6 /* Mode 6 is 1024 Hz */ +#define SAMPLE_FREQENCY ((32768 << 1) >> RTC_MODE) + /* PRIVATE FUNCTIONS *********************************************************/ +static +ULONG64 +DoLinearRegression( + ULONG XMax, + ULONG64 *ArrayY) +{ + ULONG X, SumXX; + ULONG64 SumXY; + + /* Calculate the sum of the squares of X */ + SumXX = (XMax * (XMax + 1) * (2*XMax + 1)) / 6; + + /* Calculate the sum of the differences to the first value + weighted by x */ + for (SumXY = 0, X = 1; X <= XMax; X++) + { + SumXY += X * (ArrayY[X] - ArrayY[0]); + } + + /* Account for sample frequency */ + SumXY *= SAMPLE_FREQENCY; + + /* Return the quotient of the sums */ + return (SumXY + (SumXX/2)) / SumXX; +} + VOID NTAPI HalpInitializeTsc() @@ -45,9 +74,9 @@ HalpInitializeTsc() RegisterB = HalpReadCmos(RTC_REGISTER_B); HalpWriteCmos(RTC_REGISTER_B, RegisterB | RTC_REG_B_PI); - /* Modify register A to get 4096 Hz */ + /* Modify register A to RTC_MODE to get SAMPLE_FREQENCY */ RegisterA = HalpReadCmos(RTC_REGISTER_A); - RegisterA = (RegisterA & 0xF0) | 9; + RegisterA = (RegisterA & 0xF0) | RTC_MODE; HalpWriteCmos(RTC_REGISTER_A, RegisterA); /* Save old IDT entry */ @@ -80,8 +109,9 @@ HalpInitializeTsc() /* Restore old IDT entry */ *IdtPointer = OldIdtEntry; - // do linear regression - + /* Calculate an average, using simplified linear regression */ + HalpCpuClockFrequency.QuadPart = DoLinearRegression(NUM_SAMPLES - 1, + TscCalibrationArray); /* Restore flags */ __writeeflags(Flags); @@ -133,7 +163,7 @@ KeStallExecutionProcessor(ULONG MicroSeconds) StartTime = __rdtsc(); /* Calculate the ending time */ - EndTime = StartTime + HalpCpuClockFrequency.QuadPart * MicroSeconds; + EndTime = StartTime + KeGetPcr()->StallScaleFactor * MicroSeconds; /* Loop until time is elapsed */ while (__rdtsc() < EndTime);