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

XFESystem

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

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

public static unsafe class LocalApicTimer
{
    static ulong _base;
    static bool _x2;
    public static bool Ready;
    static ulong* _ticks;
    public static ulong Ticks => _ticks == null ? 0 : *_ticks;
    static uint Read(uint register) => _x2 ? (uint)Native.ReadMsr(0x800 + register / 16) : Native.MmioRead32(_base + register);
    static void Write(uint register, uint value)
    {
        if (_x2) Native.WriteMsr(0x800 + register / 16, value);
        else Native.MmioWrite32(_base + register, value);
    }
    public static bool Initialize()
    {
        uint* cpu = stackalloc uint[4];
        Native.CpuId(1, 0, cpu);
        if ((cpu[3] & (1u << 9)) == 0 || !MonotonicClock.Ready) return false;
        _ticks = (ulong*)Native.Storage(14);
        if (_ticks == null) return false;
        *_ticks = 0;
        ulong apic = Native.ReadMsr(0x1b);
        _x2 = (apic & (1UL << 10)) != 0;
        Native.WriteMsr(0x1b, apic | (1UL << 11));
        if (!_x2)
        {
            _base = VirtualMemory.MapDevice(apic & 0xfffff000, 4096);
            if (_base == 0) return false;
        }
        Native.Out8(0x21, 255); Native.Out8(0xa1, 255); // PS/2 is polled; legacy PIC IRQs stay masked.
        Write(0xf0, 0x1ff);
        Write(0x3e0, 3); // divide by 16
        Write(0x320, (1u << 16) | 32);
        Write(0x380, 0xffffffff);
        ulong start = MonotonicClock.Nanoseconds();
        bool elapsed = false;
        for (uint poll = 0; poll < 5000000; poll++)
        {
            if (MonotonicClock.Nanoseconds() - start >= 20000000) { elapsed = true; break; }
            Native.Pause();
        }
        uint count = 0xffffffff - Read(0x390);
        if (!elapsed || count < 100) return false;
        Write(0x320, (1u << 17) | 32);
        Write(0x380, count / 2); // measured 10 ms quantum
        Ready = true;
        return true;
    }
    public static void Acknowledge() { if (Ready) Write(0xb0, 0); }
    public static void Tick() { if (_ticks != null) (*_ticks)++; Acknowledge(); }
}