mirror of
https://github.com/reactos/reactos.git
synced 2025-08-02 06:05:48 +00:00
[HAL]
- Rewrite KeQueryPerformanceCounter in C - Implement support for changing the clock rate svn path=/trunk/; revision=53495
This commit is contained in:
parent
79517b3d28
commit
e03d0348d9
2 changed files with 188 additions and 263 deletions
|
@ -64,38 +64,38 @@ _HalpCalibrateStallExecution@0:
|
|||
/* Save EFLAGS and kill interrupts */
|
||||
pushfd
|
||||
cli
|
||||
|
||||
|
||||
/* Get the current interrupt mask on the PICs */
|
||||
xor eax, eax
|
||||
in al, PIC2_DATA
|
||||
shl eax, 8
|
||||
in al, PIC1_DATA
|
||||
|
||||
|
||||
/* Save it */
|
||||
push eax
|
||||
|
||||
|
||||
/* Now mask everything except the RTC and PIC 2 chain-interrupt */
|
||||
mov eax, NOT (HEX(04) OR HEX(100))
|
||||
|
||||
|
||||
/* Program the PICs */
|
||||
out PIC1_DATA, al
|
||||
shr eax, 8
|
||||
out PIC2_DATA, al
|
||||
|
||||
|
||||
/* Now get the IDT */
|
||||
sidt [ebp-8]
|
||||
mov ecx, [ebp-6]
|
||||
|
||||
|
||||
/* Get the IDT entry for the RTC */
|
||||
mov eax, HEX(38)
|
||||
shl eax, 3
|
||||
add ecx, eax
|
||||
|
||||
|
||||
/* Save the original RTC ISR */
|
||||
push [ecx]
|
||||
push [ecx+4]
|
||||
push ecx
|
||||
|
||||
|
||||
/* Now load our new handler */
|
||||
mov eax, offset OnlyOnePersonCanWriteHalCode
|
||||
mov [ecx], ax
|
||||
|
@ -106,10 +106,10 @@ _HalpCalibrateStallExecution@0:
|
|||
|
||||
/* Reset our counter */
|
||||
mov dword ptr [ebp-12], 0
|
||||
|
||||
|
||||
/* Acquire CMOS lock */
|
||||
call _HalpAcquireSystemHardwareSpinLock@0
|
||||
|
||||
|
||||
/* Now initialize register A on the CMOS */
|
||||
mov ax, HEX(2D00) OR CMOS_REGISTER_A
|
||||
out CMOS_ADDR, al
|
||||
|
@ -117,21 +117,21 @@ _HalpCalibrateStallExecution@0:
|
|||
mov al, ah
|
||||
out CMOS_DATA, al
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Read register B */
|
||||
mov ax, CMOS_REGISTER_B
|
||||
out CMOS_ADDR, al
|
||||
jmp $+2
|
||||
in al, CMOS_DATA
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Don't touch the LastKnownGoodConfig hack */
|
||||
and al, 1
|
||||
mov ah, al
|
||||
|
||||
|
||||
/* Enable the interrupt */
|
||||
or ah, HEX(42)
|
||||
|
||||
|
||||
/* Now write the register B */
|
||||
mov al, CMOS_REGISTER_B
|
||||
out CMOS_ADDR, al
|
||||
|
@ -139,47 +139,47 @@ _HalpCalibrateStallExecution@0:
|
|||
mov al, ah
|
||||
out CMOS_DATA, al
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Read register C */
|
||||
mov al, CMOS_REGISTER_C
|
||||
out CMOS_ADDR, al
|
||||
jmp $+2
|
||||
in al, CMOS_DATA
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Read register D */
|
||||
mov al, CMOS_REGISTER_D
|
||||
out CMOS_ADDR, al
|
||||
jmp $+2
|
||||
in al, CMOS_DATA
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Release CMOS lock */
|
||||
mov dword ptr [ebp-12], 0
|
||||
call _HalpReleaseCmosSpinLock@0
|
||||
|
||||
|
||||
/* Initialize looper */
|
||||
xor eax, eax
|
||||
|
||||
|
||||
/* Align to 16 bytes */
|
||||
.align 16
|
||||
|
||||
|
||||
/* Enable interrupts! */
|
||||
sti
|
||||
jmp Looper
|
||||
|
||||
|
||||
/* Align to 16 bytes */
|
||||
.align 16
|
||||
|
||||
|
||||
/* Subtract one count */
|
||||
Looper:
|
||||
sub eax, 1
|
||||
jnz Looper
|
||||
|
||||
|
||||
/* ASSERT: If we got here, then the RTC never fired */
|
||||
call _DbgBreakPoint@0
|
||||
jmp Looper
|
||||
|
||||
|
||||
OnlyOnePersonCanWriteHalCode:
|
||||
/*********************** THIS IS THE RTC HANDLER **************************/
|
||||
|
||||
|
@ -187,17 +187,17 @@ OnlyOnePersonCanWriteHalCode:
|
|||
inc dword ptr [ebp-12]
|
||||
cmp dword ptr [ebp-12], 1
|
||||
jnz ComputeStall
|
||||
|
||||
|
||||
/*
|
||||
* It is the first one -- we'll ignore it, since it fires randomly!
|
||||
* Get rid of the old return address and push the new one in (our looper)
|
||||
*/
|
||||
pop eax
|
||||
push offset Looper
|
||||
|
||||
|
||||
/* Acquire CMOS lock */
|
||||
call _HalpAcquireSystemHardwareSpinLock@0
|
||||
|
||||
|
||||
/* Now initialize register A on the CMOS */
|
||||
mov ax, HEX(2D00) OR CMOS_REGISTER_A
|
||||
out CMOS_ADDR, al
|
||||
|
@ -205,21 +205,21 @@ OnlyOnePersonCanWriteHalCode:
|
|||
mov al, ah
|
||||
out CMOS_DATA, al
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Read register B */
|
||||
mov ax, CMOS_REGISTER_B
|
||||
out CMOS_ADDR, al
|
||||
jmp $+2
|
||||
in al, CMOS_DATA
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Don't touch the LastKnownGoodConfig hack */
|
||||
and al, 1
|
||||
mov ah, al
|
||||
|
||||
|
||||
/* Enable the interrupt */
|
||||
or ah, HEX(42)
|
||||
|
||||
|
||||
/* Now write the register B */
|
||||
mov al, CMOS_REGISTER_B
|
||||
out CMOS_ADDR, al
|
||||
|
@ -227,34 +227,34 @@ OnlyOnePersonCanWriteHalCode:
|
|||
mov al, ah
|
||||
out CMOS_DATA, al
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Read register C */
|
||||
mov al, CMOS_REGISTER_C
|
||||
out CMOS_ADDR, al
|
||||
jmp $+2
|
||||
in al, CMOS_DATA
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Read register D */
|
||||
mov al, CMOS_REGISTER_D
|
||||
out CMOS_ADDR, al
|
||||
jmp $+2
|
||||
in al, CMOS_DATA
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Release CMOS lock */
|
||||
call _HalpReleaseCmosSpinLock@0
|
||||
|
||||
|
||||
/* Dismiss the interrupt */
|
||||
mov al, PIC_EOI
|
||||
out PIC2_COMMAND, al
|
||||
mov al, PIC_SPECIFIC_EOI2
|
||||
out PIC1_COMMAND, al
|
||||
|
||||
|
||||
/* Reset the counter and return back to the looper */
|
||||
xor eax, eax
|
||||
iretd
|
||||
|
||||
|
||||
/******************* THIS IS THE 2ND RTC HANDLER **************************/
|
||||
ComputeStall:
|
||||
|
||||
|
@ -263,26 +263,26 @@ ComputeStall:
|
|||
xor edx, edx
|
||||
mov ecx, 125000 /* RTC fires every 125 ms */
|
||||
div ecx
|
||||
|
||||
|
||||
/* Is the remainder 0? */
|
||||
cmp edx, 0
|
||||
jz FoundFactor
|
||||
|
||||
|
||||
/* Otherwise fix-up the loop count */
|
||||
inc eax
|
||||
|
||||
|
||||
FoundFactor:
|
||||
/* Save the stall scale factor */
|
||||
mov fs:[KPCR_STALL_SCALE_FACTOR], eax
|
||||
|
||||
|
||||
/* Prepare for interrupt return */
|
||||
pop eax
|
||||
push offset AndItsNotYou
|
||||
mov eax, HEX(13)
|
||||
|
||||
|
||||
/* Acquire CMOS lock */
|
||||
call _HalpAcquireSystemHardwareSpinLock@0
|
||||
|
||||
|
||||
/* Now initialize register A on the CMOS */
|
||||
mov ax, HEX(2D00) OR CMOS_REGISTER_A
|
||||
out CMOS_ADDR, al
|
||||
|
@ -290,21 +290,21 @@ FoundFactor:
|
|||
mov al, ah
|
||||
out CMOS_DATA, al
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Read register B */
|
||||
mov ax, CMOS_REGISTER_B
|
||||
out CMOS_ADDR, al
|
||||
jmp $+2
|
||||
in al, CMOS_DATA
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Don't touch the LastKnownGoodConfig hack */
|
||||
and al, 1
|
||||
mov ah, al
|
||||
|
||||
|
||||
/* Disable the interrupt */
|
||||
or ah, 2
|
||||
|
||||
|
||||
/* Now write the register B */
|
||||
mov al, CMOS_REGISTER_B
|
||||
out CMOS_ADDR, al
|
||||
|
@ -312,27 +312,27 @@ FoundFactor:
|
|||
mov al, ah
|
||||
out CMOS_DATA, al
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Read register C */
|
||||
mov al, CMOS_REGISTER_C
|
||||
out CMOS_ADDR, al
|
||||
jmp $+2
|
||||
in al, CMOS_DATA
|
||||
jmp $+2
|
||||
|
||||
|
||||
/* Release CMOS lock */
|
||||
call _HalpReleaseCmosSpinLock@0
|
||||
|
||||
|
||||
/* Dismiss the interrupt */
|
||||
mov al, PIC_EOI
|
||||
out PIC2_COMMAND, al
|
||||
mov al, PIC_SPECIFIC_EOI2
|
||||
out PIC1_COMMAND, al
|
||||
|
||||
|
||||
/* Disable interrupts on return */
|
||||
and word ptr [esp+8], NOT EFLAGS_INTERRUPT_MASK
|
||||
iretd
|
||||
|
||||
|
||||
/************************* WE ARE BACK FROM RTC ***************************/
|
||||
AndItsNotYou:
|
||||
|
||||
|
@ -340,16 +340,16 @@ AndItsNotYou:
|
|||
pop ecx
|
||||
pop [ecx+4]
|
||||
pop [ecx]
|
||||
|
||||
|
||||
/* Restore the mask */
|
||||
pop eax
|
||||
out PIC1_DATA, al
|
||||
shr eax, 8
|
||||
out PIC2_DATA, al
|
||||
|
||||
|
||||
/* Restore EFLAGS */
|
||||
popf
|
||||
|
||||
popfd
|
||||
|
||||
/* Restore stack and return */
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
|
@ -368,9 +368,6 @@ _KeStallExecutionProcessor@4:
|
|||
mov eax, fs:[KPCR_STALL_SCALE_FACTOR]
|
||||
mul ecx
|
||||
|
||||
/* Align to 16 bytes */
|
||||
.align 16
|
||||
|
||||
/* Jump to subtraction loop */
|
||||
jmp SubtractLoop
|
||||
|
||||
|
@ -387,165 +384,4 @@ Done:
|
|||
ret 4
|
||||
#endif
|
||||
|
||||
PUBLIC _KeQueryPerformanceCounter@4
|
||||
_KeQueryPerformanceCounter@4:
|
||||
|
||||
/* Check if we were called too early */
|
||||
cmp dword ptr _HalpCurrentRollOver, 0
|
||||
je NoCount
|
||||
|
||||
/* Save volatiles */
|
||||
push ebx
|
||||
push esi
|
||||
|
||||
LoopPreInt:
|
||||
|
||||
/* Disable interrupts */
|
||||
pushf
|
||||
cli
|
||||
|
||||
LoopPostInt:
|
||||
|
||||
/* Get the current value */
|
||||
mov ebx, dword ptr _HalpPerfCounterLow
|
||||
mov esi, dword ptr _HalpPerfCounterHigh
|
||||
|
||||
/* Read 8254 timer */
|
||||
mov al, 0 /* Interrupt on terminal count */
|
||||
out PIT_MODE, al
|
||||
in al, SYSTEM_CTRL_PORT_A
|
||||
or al, byte ptr _HalpPerfCounterCutoff
|
||||
out SYSTEM_CTRL_PORT_A, al
|
||||
jmp $+2
|
||||
in al, PIT_CH0
|
||||
jmp $+2
|
||||
movzx ecx, al
|
||||
in al, PIT_CH0
|
||||
mov ch, al
|
||||
|
||||
/* Enable interrupts and do a short wait */
|
||||
popf
|
||||
nop
|
||||
jmp $+2
|
||||
|
||||
/* Disable them again */
|
||||
pushf
|
||||
cli
|
||||
|
||||
/* Get the counter value again */
|
||||
mov eax, dword ptr _HalpPerfCounterLow
|
||||
mov edx, dword ptr _HalpPerfCounterHigh
|
||||
|
||||
/* Check if someone updated the counter */
|
||||
cmp eax, ebx
|
||||
jnz LoopPostInt
|
||||
cmp edx, esi
|
||||
jnz LoopPostInt
|
||||
|
||||
/* Check if the current 8254 value causes rollover */
|
||||
neg ecx
|
||||
add ecx, dword ptr _HalpCurrentRollOver
|
||||
jnb DoRollOver
|
||||
|
||||
SetSum:
|
||||
|
||||
/* Calculate the sum */
|
||||
add eax, ecx
|
||||
adc edx, 0
|
||||
|
||||
/* Check if we're above or below the last high value */
|
||||
cmp edx, dword ptr _HalpLastPerfCounterHigh
|
||||
jb short BelowHigh
|
||||
jnz short BelowLow
|
||||
|
||||
/* Check if we're above or below the last low value */
|
||||
cmp eax, dword ptr _HalpLastPerfCounterLow
|
||||
jb BelowHigh
|
||||
|
||||
BelowLow:
|
||||
|
||||
/* Update the last value and bring back interrupts */
|
||||
mov dword ptr _HalpLastPerfCounterLow, eax
|
||||
mov dword ptr _HalpLastPerfCounterHigh, edx
|
||||
popf
|
||||
|
||||
/* Check if caller wants frequency */
|
||||
cmp dword ptr [esp+12], 0
|
||||
jz ReturnNoFreq
|
||||
|
||||
/* Save hard-coded frequency */
|
||||
mov ecx, dword ptr [esp+12]
|
||||
mov dword ptr [ecx], 1193182
|
||||
mov dword ptr [ecx+4], 0
|
||||
|
||||
ReturnNoFreq:
|
||||
|
||||
/* Restore volatiles */
|
||||
pop esi
|
||||
pop ebx
|
||||
ret 4
|
||||
|
||||
NoCount:
|
||||
|
||||
/* Return empty, called too soon */
|
||||
mov eax, 0
|
||||
mov edx, 0
|
||||
ret 4
|
||||
|
||||
DoRollOver:
|
||||
|
||||
/* We might have an incoming interrupt, save EFLAGS and reset rollover */
|
||||
mov esi, [esp]
|
||||
mov ecx, dword ptr _HalpCurrentRollOver
|
||||
popf
|
||||
|
||||
/* Check if interrupts were enabled and try again */
|
||||
test esi, EFLAGS_INTERRUPT_MASK
|
||||
jnz LoopPreInt
|
||||
|
||||
/* They're not, continue where we left */
|
||||
pushf
|
||||
jmp SetSum
|
||||
|
||||
BelowHigh:
|
||||
|
||||
/* Get the last counter values */
|
||||
mov ebx, dword ptr _HalpLastPerfCounterLow
|
||||
mov esi, dword ptr _HalpLastPerfCounterHigh
|
||||
|
||||
/* Check if the previous value was 0 and go back if yes */
|
||||
mov ecx, ebx
|
||||
or ecx, esi
|
||||
jz BelowLow
|
||||
|
||||
/* Make sure that the count is still valid */
|
||||
sub ebx, eax
|
||||
sbb esi, edx
|
||||
jnz InvalidCount
|
||||
cmp ebx, dword ptr _HalpCurrentRollOver
|
||||
jg InvalidCount
|
||||
|
||||
/* Fixup the count with the last known value */
|
||||
sub eax, ebx
|
||||
sbb edx, esi
|
||||
|
||||
/* We might have an incoming interrupt, save EFLAGS */
|
||||
mov ecx, [esp]
|
||||
popf
|
||||
|
||||
/* Check if interrupts were enabled and try again */
|
||||
test ecx, EFLAGS_INTERRUPT_MASK
|
||||
jnz LoopPreInt
|
||||
|
||||
/* They're not, continue where we left */
|
||||
pushf
|
||||
jmp BelowLow
|
||||
|
||||
InvalidCount:
|
||||
popf
|
||||
xor eax, eax
|
||||
mov dword ptr _HalpLastPerfCounterLow, eax
|
||||
mov dword ptr _HalpLastPerfCounterHigh, eax
|
||||
jmp LoopPreInt
|
||||
|
||||
END
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* FILE: hal/halx86/generic/timer.c
|
||||
* PURPOSE: HAL Timer Routines
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
* Timo Kreuzer (timo.kreuzer@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
@ -14,6 +15,9 @@
|
|||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
#define PIT_LATCH 0x00
|
||||
|
||||
LARGE_INTEGER HalpLastPerfCounter;
|
||||
ULONG HalpPerfCounterCutoff;
|
||||
BOOLEAN HalpClockSetMSRate;
|
||||
ULONG HalpCurrentTimeIncrement;
|
||||
|
@ -21,54 +25,56 @@ ULONG HalpCurrentRollOver;
|
|||
ULONG HalpNextMSRate = 14;
|
||||
ULONG HalpLargestClockMS = 15;
|
||||
|
||||
LARGE_INTEGER HalpRolloverTable[15] =
|
||||
static struct _HALP_ROLLOVER
|
||||
{
|
||||
{{1197, 10032}},
|
||||
{{2394, 20064}},
|
||||
{{3591, 30096}},
|
||||
{{4767, 39952}},
|
||||
{{5964, 49984}},
|
||||
{{7161, 60016}},
|
||||
{{8358, 70048}},
|
||||
{{9555, 80080}},
|
||||
{{10731, 89936}},
|
||||
{{11949, 100144}},
|
||||
{{13125, 110000}},
|
||||
{{14322, 120032}},
|
||||
{{15519, 130064}},
|
||||
{{16695, 139920}},
|
||||
{{17892, 149952}}
|
||||
ULONG RollOver;
|
||||
ULONG Increment;
|
||||
} HalpRolloverTable[15] =
|
||||
{
|
||||
{1197, 10032},
|
||||
{2394, 20064},
|
||||
{3591, 30096},
|
||||
{4767, 39952},
|
||||
{5964, 49984},
|
||||
{7161, 60016},
|
||||
{8358, 70048},
|
||||
{9555, 80080},
|
||||
{10731, 89936},
|
||||
{11949, 100144},
|
||||
{13125, 110000},
|
||||
{14322, 120032},
|
||||
{15519, 130064},
|
||||
{16695, 139920},
|
||||
{17892, 149952}
|
||||
};
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
FORCEINLINE
|
||||
ULONG
|
||||
HalpRead8254Value(void)
|
||||
{
|
||||
ULONG TimerValue;
|
||||
|
||||
/* Send counter latch command for channel 0 */
|
||||
__outbyte(TIMER_CONTROL_PORT, PIT_LATCH);
|
||||
__nop();
|
||||
|
||||
/* Read the value, LSB first */
|
||||
TimerValue = __inbyte(TIMER_CHANNEL0_DATA_PORT);
|
||||
__nop();
|
||||
TimerValue |= __inbyte(TIMER_CHANNEL0_DATA_PORT) << 8;
|
||||
|
||||
return TimerValue;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
INIT_FUNCTION
|
||||
HalpInitializeClock(VOID)
|
||||
HalpSetTimerRollOver(USHORT RollOver)
|
||||
{
|
||||
PKPRCB Prcb = KeGetCurrentPrcb();
|
||||
ULONG Increment;
|
||||
USHORT RollOver;
|
||||
ULONG_PTR Flags;
|
||||
TIMER_CONTROL_PORT_REGISTER TimerControl;
|
||||
|
||||
/* Check the CPU Type */
|
||||
if (Prcb->CpuType <= 4)
|
||||
{
|
||||
/* 486's or equal can't go higher then 10ms */
|
||||
HalpLargestClockMS = 10;
|
||||
HalpNextMSRate = 9;
|
||||
}
|
||||
|
||||
/* Get increment and rollover for the largest time clock ms possible */
|
||||
Increment = HalpRolloverTable[HalpLargestClockMS - 1].HighPart;
|
||||
RollOver = (USHORT)HalpRolloverTable[HalpLargestClockMS - 1].LowPart;
|
||||
|
||||
/* Set the maximum and minimum increment with the kernel */
|
||||
HalpCurrentTimeIncrement = Increment;
|
||||
KeSetTimeIncrement(Increment, HalpRolloverTable[0].HighPart);
|
||||
|
||||
/* Disable interrupts */
|
||||
Flags = __readeflags();
|
||||
_disable();
|
||||
|
@ -98,9 +104,31 @@ HalpInitializeClock(VOID)
|
|||
|
||||
/* Restore interrupts if they were previously enabled */
|
||||
__writeeflags(Flags);
|
||||
}
|
||||
|
||||
/* Save rollover and return */
|
||||
VOID
|
||||
NTAPI
|
||||
INIT_FUNCTION
|
||||
HalpInitializeClock(VOID)
|
||||
{
|
||||
ULONG Increment;
|
||||
USHORT RollOver;
|
||||
|
||||
DPRINT("HalpInitializeClock()\n");
|
||||
|
||||
/* Get increment and rollover for the largest time clock ms possible */
|
||||
Increment = HalpRolloverTable[HalpLargestClockMS - 1].Increment;
|
||||
RollOver = (USHORT)HalpRolloverTable[HalpLargestClockMS - 1].RollOver;
|
||||
|
||||
/* Set the maximum and minimum increment with the kernel */
|
||||
KeSetTimeIncrement(Increment, HalpRolloverTable[0].Increment);
|
||||
|
||||
/* Set the rollover value for the timer */
|
||||
HalpSetTimerRollOver(RollOver);
|
||||
|
||||
/* Save rollover and increment */
|
||||
HalpCurrentRollOver = RollOver;
|
||||
HalpCurrentTimeIncrement = Increment;
|
||||
}
|
||||
|
||||
#ifdef _M_IX86
|
||||
|
@ -109,6 +137,7 @@ VOID
|
|||
FASTCALL
|
||||
HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame)
|
||||
{
|
||||
ULONG LastIncrement;
|
||||
KIRQL Irql;
|
||||
|
||||
/* Enter trap */
|
||||
|
@ -121,16 +150,25 @@ HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame)
|
|||
HalpPerfCounter.QuadPart += HalpCurrentRollOver;
|
||||
HalpPerfCounterCutoff = KiEnableTimerWatchdog;
|
||||
|
||||
/* Save increment */
|
||||
LastIncrement = HalpCurrentTimeIncrement;
|
||||
|
||||
/* Check if someone changed the time rate */
|
||||
if (HalpClockSetMSRate)
|
||||
{
|
||||
/* Not yet supported */
|
||||
UNIMPLEMENTED;
|
||||
ASSERT(FALSE);
|
||||
/* Update the global values */
|
||||
HalpCurrentTimeIncrement = HalpRolloverTable[HalpNextMSRate - 1].Increment;
|
||||
HalpCurrentRollOver = HalpRolloverTable[HalpNextMSRate - 1].RollOver;
|
||||
|
||||
/* Set new timer rollover */
|
||||
HalpSetTimerRollOver((USHORT)HalpCurrentRollOver);
|
||||
|
||||
/* We're done */
|
||||
HalpClockSetMSRate = FALSE;
|
||||
}
|
||||
|
||||
/* Update the system time -- the kernel will exit this trap */
|
||||
KeUpdateSystemTime(TrapFrame, HalpCurrentTimeIncrement, Irql);
|
||||
KeUpdateSystemTime(TrapFrame, LastIncrement, Irql);
|
||||
}
|
||||
|
||||
/* Spurious, just end the interrupt */
|
||||
|
@ -206,7 +244,58 @@ HalSetTimeIncrement(IN ULONG Increment)
|
|||
HalpClockSetMSRate = TRUE;
|
||||
|
||||
/* Return the increment */
|
||||
return HalpRolloverTable[Increment - 1].HighPart;
|
||||
return HalpRolloverTable[Increment - 1].Increment;
|
||||
}
|
||||
|
||||
LARGE_INTEGER
|
||||
NTAPI
|
||||
KeQueryPerformanceCounter(PLARGE_INTEGER PerformanceFrequency)
|
||||
{
|
||||
LARGE_INTEGER CurrentPerfCounter;
|
||||
ULONG CounterValue, ClockDelta;
|
||||
|
||||
/* If caller wants performance frequency, return hardcoded value */
|
||||
if (PerformanceFrequency) PerformanceFrequency->QuadPart = PIT_FREQUENCY;
|
||||
|
||||
/* Check if we were called too early */
|
||||
if (HalpCurrentRollOver == 0) return HalpPerfCounter;
|
||||
|
||||
/* Check if interrupts are disabled */
|
||||
if(!(__readeflags() & EFLAGS_INTERRUPT_MASK)) return HalpPerfCounter;
|
||||
|
||||
do
|
||||
{
|
||||
/* Get the current performance counter value */
|
||||
CurrentPerfCounter = HalpPerfCounter;
|
||||
|
||||
/* Read the 8254 counter value */
|
||||
CounterValue = HalpRead8254Value();
|
||||
|
||||
/* Repeat if the value has changed (a clock interrupt happened) */
|
||||
} while (CurrentPerfCounter.QuadPart != HalpPerfCounter.QuadPart);
|
||||
|
||||
/* After someone changed the clock rate, during the first clock cycle we
|
||||
might see a counter value larger than the rollover. In this case we
|
||||
pretend it already has the new rollover value. */
|
||||
if (CounterValue > HalpCurrentRollOver) CounterValue = HalpCurrentRollOver;
|
||||
|
||||
/* The interrupt is issued on the falling edge of the OUT line, when the
|
||||
counter changes from 1 to max. Calculate a clock delta, so that directly
|
||||
after the interrupt it is 0, going up to (HalpCurrentRollOver - 1). */
|
||||
ClockDelta = HalpCurrentRollOver - CounterValue;
|
||||
|
||||
/* Add the clock delta */
|
||||
CurrentPerfCounter.QuadPart += ClockDelta;
|
||||
|
||||
/* This must be true unless HalpPerfCounter has changed sign,
|
||||
which takes approximately 245,118 years */
|
||||
ASSERT(CurrentPerfCounter.QuadPart >= HalpLastPerfCounter.QuadPart);
|
||||
|
||||
/* Update the last counter value */
|
||||
HalpLastPerfCounter = CurrentPerfCounter;
|
||||
|
||||
/* Return the result */
|
||||
return CurrentPerfCounter;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue