Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

308 lines
6.4 KiB

/*++
Copyright (c) 1993 Digital Equipment Corporation
Module Name:
rwclock.c
Abstract:
This module implements the code necessary to field and process the
interval clock interrupt.
Author:
Eric Rehm 1-Dec-1995
Environment:
Kernel mode only.
Revision History:
--*/
#include "halp.h"
#include "rawhide.h"
//
// Define global data used to communicate new clock rates to the clock
// interrupt service routine.
//
ULONG HalpCurrentTimeIncrement;
ULONG HalpNewTimeIncrement;
ULONG HalpNextRateSelect;
ULONG HalpCurrentRollOver[RAWHIDE_MAXIMUM_PROCESSOR+1];
ULONG HalpNextRollOver;
//
// The Rawhide Interval Timer has an accuracy of 100 ppm:
// Nominal: 833.3333 us
// Min: 833.41668 us
// Max: 833.25001 us
//
// The following clock table values indicated the number of actual
// clock interrupts we should take before we tell the system the time
// has changed (a.k.a "RollOver count"). Each RollOver count has
// and associated time increment = INT(RollOver * 833.3333 * 10)
// that is in units of 100 us.
//
// RollOver Time Nominal Error
// Count Increment MS (ms/day)
CLOCK_TABLE
HalpRollOverTable[NUM_CLOCK_RATES] =
{ {2, 16667}, // 1.667 ms
{3, 25000}, // 2.5 ms +0.864
{6, 50000}, // 5.0 ms +1.728
{9, 75000} // 7.5 ms +2.592
// {12, 100000}, // 10.0 ms +3.456
// {15, 125000}, // 12.5 ms +4.320
// {18, 150000} // 15.0 ms +5.184
// debug {1, 8334} // .8333 ms +287.7
};
BOOLEAN
HalpAcknowledgeRawhideClockInterrupt(
VOID
)
/*++
Routine Description:
Acknowledge the clock interrupt from the interval timer. The interval
timer for Rawhide comes from an onboard oscillator, divided down
by the processor.
Arguments:
None.
Return Value:
None.
--*/
{
MC_DEVICE_ID McDeviceId;
PKPRCB Prcb;
//
// Avoid a WhoAmI register read by using the PCR
//
Prcb = PCR->Prcb;
McDeviceId.all = HalpLogicalToPhysicalProcessor[Prcb->Number].all;
//
// Acknownledge the clock interrupt by writing to our own
// clock interrupt acknowledge.
//
CPU_CLOCK_ACKNOWLEDGE( McDeviceId );
//
// Has the roll-over counter expired for this processor's clock?
//
if ( (--HalpCurrentRollOver[Prcb->Number]) == 0 ) {
//
// Yes. Reset count to latest RollOver count and
// tell caller to do something.
//
HalpCurrentRollOver[Prcb->Number] = HalpNextRollOver;
return TRUE;
}
//
// No. Tell caller to do nothing.
//
return FALSE;
}
VOID
HalpProgramIntervalTimer(
IN ULONG RateSelect
)
/*++
Routine Description:
This function is called to program the interval timer. It is used during
Phase 1 initialization to start the heartbeat timer. It also used by
the clock interrupt routine to change the hearbeat timer rate when a call
to HalSetTimeIncrement has been made in the previous time slice.
Arguments:
RateSelect - Supplies rate select to be placed in the clock.
Return Value:
None.
--*/
{
ULONG i;
//
// Set the new rate via the global "next" roll-over count.
//
// When each processor's private roll-over counter
// (HalpCurrentRollOver[i]) expires, it will be reset to the
// this global "next" roll-over count;
//
#if HALDBG
DbgPrint( "HalpProgramIntervalTimer: Set to new rate %d, RollOver %d\n",
RateSelect,
HalpRollOverTable[RateSelect-1].RollOver );
#endif // HALDBG
HalpNextRollOver = HalpRollOverTable[RateSelect-1].RollOver;
}
VOID
HalpSetTimeIncrement(
VOID
)
/*++
Routine Description:
This routine is responsible for setting the time increment for an EV5
based machine via a call into the kernel. This routine is
only called by the primary processor.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG i;
//
// Set the time increment value.
//
HalpCurrentTimeIncrement
= HalpRollOverTable[MAXIMUM_CLOCK_INCREMENT-1].TimeIncr;
for (i = 0; i <= RAWHIDE_MAXIMUM_PROCESSOR; i++) {
HalpCurrentRollOver[i] =
HalpRollOverTable[MAXIMUM_CLOCK_INCREMENT-1].RollOver;
}
HalpNextRollOver =
HalpRollOverTable[MAXIMUM_CLOCK_INCREMENT-1].RollOver;
HalpNextRateSelect = 0;
KeSetTimeIncrement( HalpRollOverTable[MAXIMUM_CLOCK_INCREMENT-1].TimeIncr,
HalpRollOverTable[MINIMUM_CLOCK_INCREMENT-1].TimeIncr);
}
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.
Arguments:
DesiredIncrement - Supplies desired number of 100ns units between clock
interrupts.
Return Value:
The actual time increment in 100ns units.
--*/
{
KIRQL OldIrql;
ULONG rate;
ULONG BestIndex;
//
// 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);
//
// Find the allowed increment that is less than or equal to
// the desired increment.
//
for (rate = 1; rate < NUM_CLOCK_RATES; rate++) {
if (DesiredIncrement < HalpRollOverTable[rate].TimeIncr) {
break;
}
}
BestIndex = rate - 1;
#if HALDBG
DbgPrint(
"HalSetTimeIncrement: Desired %d, BestIndex: %d TimeIncr %d RollOver %d \n",
DesiredIncrement,
BestIndex,
HalpRollOverTable[BestIndex].TimeIncr,
HalpRollOverTable[BestIndex].RollOver
);
#endif // HALDBG
//
// Set the new time increment and the rate select (RollOverTable index)
// that will be used on the next tick of each processor's "soft"
// clock counter (HalpCurrentRollOver[i]).
//
HalpNewTimeIncrement = HalpRollOverTable[BestIndex].TimeIncr;
HalpNextRateSelect = BestIndex + 1;
KeLowerIrql(OldIrql);
return HalpNewTimeIncrement;
}