singrdk/base/Kernel/Singularity.Hal.ApicPC/Calibrate.cs

84 lines
2.7 KiB
C#

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Note:
//
namespace Microsoft.Singularity.Hal
{
using Microsoft.Singularity.Hal.Acpi;
internal class Calibrate
{
private static uint PmDelta(uint newValue, uint oldValue)
{
// PmTimer may be 24 or 32 bits depending on system.
// Simplest to treat as 24 bits.
return (newValue - oldValue) & 0x00ffffff;
}
internal static void CpuCycleCounter(PMTimer pmTimer)
{
uint pmLast = pmTimer.Value;
ulong tscLast = Processor.CycleCount;
uint pmLimit = PMTimer.FrequencyHz / 15;
uint pmAccum = 0;
ulong tscNow = 0;
// Initial measurements
tscLast = Processor.CycleCount;
pmLast = pmTimer.Value;
// Measurement loop
do
{
tscNow = Processor.CycleCount;
uint pmNow = pmTimer.Value;
pmAccum += PmDelta(pmNow, pmLast);
pmLast = pmNow;
} while (pmAccum < pmLimit);
ulong tscHz = PMTimer.FrequencyHz * (tscNow - tscLast) / pmAccum;
DebugStub.Print("Cpu{0}: TSC frequency {1} Hz\n",
__arglist(Processor.CurrentProcessor.Id, tscHz));
Processor.CyclesPerSecond = tscHz;
}
internal static void ApicTimer(PMTimer pmTimer, ApicTimer apicTimer)
{
apicTimer.SetDivisor(1);
apicTimer.SetOneShot();
apicTimer.SetInterruptEnabled(false);
apicTimer.SetInitialCount(~0u);
uint apicLast = apicTimer.Value;
uint pmLast = pmTimer.Value;
uint pmLimit = PMTimer.FrequencyHz / 15;
uint pmAccum = 0;
uint apicNow = 0;
// Initial measurements
apicLast = apicTimer.Value;
pmLast = pmTimer.Value;
do
{
apicNow = apicTimer.Value;
uint pmNow = pmTimer.Value | 0xff000000;
pmAccum += PmDelta(pmNow, pmLast);
pmLast = pmNow;
} while (pmAccum < pmLimit);
ulong apicHz = PMTimer.FrequencyHz * (ulong)(apicLast - apicNow) / pmAccum;
DebugStub.Print("Cpu{0}: APIC timer frequency {1} Hz\n",
__arglist(Processor.CurrentProcessor.Id, apicHz));
apicTimer.SetBusFrequency((uint)apicHz);
}
}
}