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(); }
}
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(); }
}