244 lines
4.9 KiB
C
244 lines
4.9 KiB
C
|
||
/*****************************************************************************
|
||
|
||
Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file
|
||
contains copyrighted material. Use of this file is restricted
|
||
by the provisions of a Motorola Software License Agreement.
|
||
|
||
Module Name:
|
||
|
||
PXCLOCK.C
|
||
|
||
Abstract:
|
||
|
||
This module contains the system clock interrupt handler.
|
||
The DECREMENTER is used to implement the system clock. The
|
||
handler resets the DECREMENTER to SYSTEM_TIME (accounting
|
||
for interrupt latency), and updates the system time.
|
||
|
||
|
||
Author:
|
||
|
||
Steve Johns 10-Feb-1994
|
||
|
||
Revision History:
|
||
// 09-Jun-95 Steve Johns
|
||
// - Removed 1 level of buffering of time increment to match
|
||
// buffering of DECREMENTER counts.
|
||
******************************************************************************/
|
||
|
||
#include "halp.h"
|
||
|
||
extern ULONG HalpPerformanceFrequency;
|
||
|
||
BOOLEAN
|
||
KdPollBreakIn (
|
||
VOID
|
||
);
|
||
|
||
ULONG HalpClockCount;
|
||
ULONG HalpFullTickClockCount;
|
||
ULONG HalpUpdateDecrementer();
|
||
|
||
ULONG HalpCurrentTimeIncrement;
|
||
ULONG HalpNewTimeIncrement;
|
||
|
||
BOOLEAN
|
||
HalpHandleDecrementerInterrupt(
|
||
IN PKINTERRUPT Interrupt,
|
||
IN PVOID ServiceContext,
|
||
IN PVOID TrapFrame
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Clock interrupt handler for processor 0.
|
||
|
||
Arguments:
|
||
|
||
Interrupt
|
||
|
||
ServiceContext
|
||
|
||
TrapFrame
|
||
|
||
Return Value:
|
||
|
||
TRUE
|
||
|
||
--*/
|
||
{
|
||
KIRQL OldIrql;
|
||
|
||
//
|
||
// Raise irql via updating the PCR
|
||
//
|
||
|
||
OldIrql = PCR->CurrentIrql;
|
||
|
||
PCR->CurrentIrql = CLOCK2_LEVEL;
|
||
|
||
//
|
||
// Reset DECREMENTER, accounting for interrupt latency.
|
||
//
|
||
|
||
HalpUpdateDecrementer(HalpClockCount);
|
||
|
||
//
|
||
// Call the kernel to update system time
|
||
//
|
||
|
||
KeUpdateSystemTime(TrapFrame,HalpCurrentTimeIncrement);
|
||
|
||
//
|
||
// If tick rate has changed, then tell the kernel about it
|
||
//
|
||
|
||
HalpCurrentTimeIncrement = HalpNewTimeIncrement;
|
||
|
||
//
|
||
// Lower Irql to original value and enable interrupts
|
||
//
|
||
|
||
PCR->CurrentIrql = OldIrql;
|
||
|
||
HalpEnableInterrupts();
|
||
|
||
if ( KdDebuggerEnabled && KdPollBreakIn() ) {
|
||
DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
|
||
}
|
||
|
||
return (TRUE);
|
||
}
|
||
|
||
#if !defined(NT_UP)
|
||
VOID
|
||
HalpHandleDecrementerInterrupt1(
|
||
IN PKINTERRUPT Interrupt,
|
||
IN PVOID ServiceContext,
|
||
IN PVOID TrapFrame
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Clock interrupt handler for processors other than 0.
|
||
|
||
Arguments:
|
||
|
||
Interrupt
|
||
|
||
ServiceContext
|
||
|
||
TrapFrame
|
||
|
||
Return Value:
|
||
|
||
TRUE
|
||
|
||
--*/
|
||
{
|
||
|
||
KIRQL OldIrql;
|
||
|
||
//
|
||
// Raise irql via updating the PCR
|
||
//
|
||
|
||
OldIrql = PCR->CurrentIrql;
|
||
|
||
PCR->CurrentIrql = CLOCK2_LEVEL;
|
||
|
||
//
|
||
// Reset DECREMENTER, accounting for interrupt latency.
|
||
//
|
||
|
||
HalpUpdateDecrementer(HalpFullTickClockCount);
|
||
|
||
//
|
||
// Call the kernel to update run time for this thread and process.
|
||
//
|
||
|
||
KeUpdateRunTime(TrapFrame);
|
||
|
||
//
|
||
// Lower Irql to original value
|
||
//
|
||
|
||
PCR->CurrentIrql = OldIrql;
|
||
|
||
return;
|
||
}
|
||
#endif
|
||
|
||
ULONG
|
||
HalSetTimeIncrement (
|
||
IN ULONG DesiredIncrement
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to set the clock interrupt rate to the frequency
|
||
required by the specified time increment value.
|
||
|
||
N.B. This function is only executed on the processor that keeps the
|
||
system time.
|
||
|
||
Arguments:
|
||
|
||
DesiredIncrement - Supplies desired number of 100ns units between clock
|
||
interrupts.
|
||
|
||
Return Value:
|
||
|
||
The actual time increment in 100ns units.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
KIRQL OldIrql;
|
||
|
||
//
|
||
// Raise IRQL to the highest level, set the new clock interrupt
|
||
// parameters, lower IRQl, and return the new time increment value.
|
||
//
|
||
|
||
|
||
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
||
|
||
//
|
||
// HalpPerformanceFrequence is the number of times the decrementer
|
||
// ticks in 1 second. MINIMUM_INCREMENT is the number of 100 is the
|
||
// number of 100ns units in 1 ms.
|
||
// Therefore, DesiredIncrement/MINUMUM_INCREMENT is the number of
|
||
// ms desired. This multiplied by the number of decrementer ticks
|
||
// in 1 second, divided by 1000 gives the number of ticks in the
|
||
// desired number of milliseconds. This value will go into the
|
||
// decrementer.
|
||
//
|
||
|
||
HalpClockCount = (HalpPerformanceFrequency *
|
||
(DesiredIncrement/MINIMUM_INCREMENT)) / 1000;
|
||
|
||
//
|
||
// Calculate the number of 100ns units to report to the kernel every
|
||
// time the decrementer fires with this new period. Note, for small
|
||
// values of DesiredIncrement (min being 10000, ie 1ms), truncation
|
||
// in the above may result in a small decrement in the 5th decimal
|
||
// place. As we are effectively dealing with a 4 digit number, eg
|
||
// 10000 becomes 9999.something, we really can't do any better than
|
||
// the following.
|
||
//
|
||
|
||
HalpNewTimeIncrement = DesiredIncrement/MINIMUM_INCREMENT * MINIMUM_INCREMENT;
|
||
|
||
KeLowerIrql(OldIrql);
|
||
return HalpNewTimeIncrement;
|
||
}
|