XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
namespace XFESystem.NativeKernel;

// Single-BSP elapsed-time source. CPUID crystal/ratio is preferred; otherwise
// channel 2 of the legacy PIT measures TSC frequency without enabling an IRQ.
public static unsafe class MonotonicClock
{
    public static ulong Frequency;
    public static bool Ready, Invariant;
    static ulong _origin;

    public static bool Initialize()
    {
        Frequency = 0;
        uint* result = stackalloc uint[4];
        Native.CpuId(0x80000000, 0, result);
        if (result[0] >= 0x80000007)
        {
            Native.CpuId(0x80000007, 0, result);
            Invariant = (result[3] & (1u << 8)) != 0;
        }
        if (Cpu.MaximumLeaf >= 0x15)
        {
            Native.CpuId(0x15, 0, result);
            if (result[0] != 0 && result[1] != 0 && result[2] != 0)
                Frequency = (ulong)result[2] * result[1] / result[0];
        }
        if (Frequency == 0) Frequency = CalibratePit();
        if (Frequency < 1000000 || Frequency > 10000000000) return false;
        _origin = Native.ReadTsc();
        Ready = true;
        ulong before = Nanoseconds();
        for (uint i = 0; i < 1000; i++) Native.Pause();
        return Nanoseconds() >= before;
    }

    static ulong CalibratePit()
    {
        const ushort ticks = 11932;
        byte original = Native.In8(0x61);
        if (original == 0xff) return 0;
        Native.Out8(0x61, (byte)(original & ~3));
        Native.Out8(0x43, 0xb0); // channel 2, lo/hi, mode zero, binary
        Native.Out8(0x42, (byte)(ticks & 255));
        Native.Out8(0x42, (byte)(ticks >> 8));
        ulong start = Native.ReadTsc();
        Native.Out8(0x61, (byte)((original & ~2) | 1));
        bool complete = false;
        for (uint poll = 0; poll < 2000000; poll++)
        {
            if ((Native.In8(0x61) & 0x20) != 0) { complete = true; break; }
            Native.Pause();
        }
        ulong elapsed = Native.ReadTsc() - start;
        Native.Out8(0x61, original);
        if (!complete || elapsed > 100000000000UL) return 0;
        return elapsed * 1193182 / ticks;
    }

    public static ulong Nanoseconds()
    {
        if (!Ready) return 0;
        ulong elapsed = Native.ReadTsc() - _origin;
        return elapsed / Frequency * 1000000000 + elapsed % Frequency * 1000000000 / Frequency;
    }
}