86 lines
2.8 KiB
C#
86 lines
2.8 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// Note:
|
||
|
//
|
||
|
// HalClock is expected to call PMClock's time maintenance
|
||
|
// functions with a spin lock held.
|
||
|
|
||
|
namespace Microsoft.Singularity.Hal
|
||
|
{
|
||
|
using Microsoft.Singularity.Hal.Acpi;
|
||
|
|
||
|
using System;
|
||
|
using System.Diagnostics;
|
||
|
using System.Runtime.CompilerServices;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using System.Threading;
|
||
|
|
||
|
[ CLSCompliant(false) ]
|
||
|
internal class PMClock
|
||
|
{
|
||
|
PMTimer pmTimer;
|
||
|
ulong kernelTicksTotal;
|
||
|
ulong pmResidual;
|
||
|
uint pmLastUpdate;
|
||
|
|
||
|
internal PMClock(PMTimer timer)
|
||
|
{
|
||
|
this.pmTimer = timer;
|
||
|
this.kernelTicksTotal = 0;
|
||
|
this.pmResidual = 0;
|
||
|
this.pmLastUpdate = pmTimer.Value;
|
||
|
}
|
||
|
|
||
|
[NoHeapAllocation]
|
||
|
private static ulong PMTicksToKernelTicks(ulong pmTicks)
|
||
|
{
|
||
|
// REVIEW: Does this need to be a ulong?
|
||
|
//
|
||
|
// PM frequency is 3579545Hz. Kernel tick frequency is 10MHz.
|
||
|
// The conversion is:
|
||
|
// kTicks = pmTicks * 10000000 / 3579545
|
||
|
// = pmTicks * (2 + 0xcb2cb8bed / 0x1000000000)
|
||
|
// = pmTicks * (0x2cb / 0x100 + 0x2cb / 0x100000 +
|
||
|
// 0x8bed / 0x1000000000)
|
||
|
ulong tmp = pmTicks * 0x2cb;
|
||
|
return (tmp >> 8) + (tmp >> 20) + ((pmTicks * 0x8bed) >> 36);
|
||
|
}
|
||
|
|
||
|
[NoHeapAllocation]
|
||
|
private static uint PmDeltaTicks(uint pmNow, uint pmLast)
|
||
|
{
|
||
|
// We unconditionally round down to 24-bits as
|
||
|
// values from PM timer may be 24-bit or 32-bit.
|
||
|
return (pmNow - pmLast) & 0xffffff;
|
||
|
}
|
||
|
|
||
|
[NoHeapAllocation]
|
||
|
internal ulong GetKernelTicks()
|
||
|
{
|
||
|
uint pmNow = pmTimer.Value;
|
||
|
uint pmDelta = PmDeltaTicks(pmNow, this.pmLastUpdate);
|
||
|
return this.kernelTicksTotal +
|
||
|
PMTicksToKernelTicks(this.pmResidual + pmDelta);
|
||
|
}
|
||
|
|
||
|
[NoHeapAllocation]
|
||
|
internal void Update()
|
||
|
{
|
||
|
uint pmNow = pmTimer.Value;
|
||
|
this.pmResidual += PmDeltaTicks(pmNow, this.pmLastUpdate);
|
||
|
// Transfer time from residual to accumulated
|
||
|
// time in one second intervals since there is
|
||
|
// an integral relationship between the two.
|
||
|
while (this.pmResidual >= PMTimer.FrequencyHz) {
|
||
|
this.kernelTicksTotal += 10000000; // Kernel tick freq
|
||
|
this.pmResidual -= PMTimer.FrequencyHz;
|
||
|
}
|
||
|
this.pmLastUpdate = pmNow;
|
||
|
}
|
||
|
}
|
||
|
}
|