using System.Runtime.InteropServices; namespace XFESystem.NativeKernel; // Live CMOS RTC, not a compile timestamp or host clock. The virtual-machine // launch must configure RTC base=utc. Physical firmware RTC timezone conventions // require separate validation; CMOS itself contains no trustworthy timezone. public static unsafe class UtcClock { const uint PollLimit = 100000; static byte ReadRegister(byte index, byte nmiMask) { Native.Out8(0x70, (byte)(nmiMask | index)); return Native.In8(0x71); } static bool Sample(byte nmiMask, out ulong value) { value = 0; bool stable = false; for (uint poll = 0; poll < PollLimit; poll++) { byte status = ReadRegister(0x0a, nmiMask); if (status == 255) return false; if ((status & 0x80) == 0) { stable = true; break; } Native.Pause(); } if (!stable || (ReadRegister(0x0d, nmiMask) & 0x80) == 0) return false; value = ReadRegister(0, nmiMask); value |= (ulong)ReadRegister(2, nmiMask) << 8; value |= (ulong)ReadRegister(4, nmiMask) << 16; value |= (ulong)ReadRegister(7, nmiMask) << 24; value |= (ulong)ReadRegister(8, nmiMask) << 32; value |= (ulong)ReadRegister(9, nmiMask) << 40; value |= (ulong)ReadRegister(0x32, nmiMask) << 48; // Conventional PC century; invalid/unset values use documented pivot. value |= (ulong)ReadRegister(0x0b, nmiMask) << 56; return (ReadRegister(0x0a, nmiMask) & 0x80) == 0; } static uint Decode(byte value, bool binary) { if (binary) return value; if ((value & 15) > 9 || (value >> 4) > 9) return 0xffffffff; return (uint)((value >> 4) * 10 + (value & 15)); } static bool Leap(uint year) => year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); static uint DaysInMonth(uint year, uint month) { if (month == 2) return Leap(year) ? 29u : 28u; if (month == 4 || month == 6 || month == 9 || month == 11) return 30; return 31; } static ulong DaysBeforeYear(uint year) { ulong y = year - 1; return 365 * y + y / 4 - y / 100 + y / 400; } static ulong Convert(ulong value) { byte status = (byte)(value >> 56); if (status == 255 || (status & 0x80) != 0) return 0; // SET inhibits clock updates; never label a frozen RTC as live. bool binary = (status & 4) != 0, twentyFour = (status & 2) != 0; uint second = Decode((byte)value, binary), minute = Decode((byte)(value >> 8), binary); byte rawHour = (byte)(value >> 16); uint hour = Decode((byte)(rawHour & 0x7f), binary); if (!twentyFour) { if (hour < 1 || hour > 12) return 0; hour = hour % 12 + ((rawHour & 0x80) != 0 ? 12u : 0u); } else if ((rawHour & 0x80) != 0) return 0; uint day = Decode((byte)(value >> 24), binary), month = Decode((byte)(value >> 32), binary); uint shortYear = Decode((byte)(value >> 40), binary), century = Decode((byte)(value >> 48), binary); if (second > 59 || minute > 59 || hour > 23 || month < 1 || month > 12 || shortYear > 99) return 0; uint year = century >= 19 && century <= 99 ? century * 100 + shortYear : shortYear < 70 ? 2000 + shortYear : 1900 + shortYear; if (year < 1601 || year > 9999 || day < 1 || day > DaysInMonth(year, month)) return 0; ulong days = DaysBeforeYear(year) - DaysBeforeYear(1601); for (uint m = 1; m < month; m++) days += DaysInMonth(year, m); days += day - 1; return (days * 86400 + hour * 3600UL + minute * 60UL + second) * 10000000; } public static ulong ReadFileTime() { ulong flags = Native.IrqSave(); byte originalSelector = Native.In8(0x70), nmiMask = (byte)(originalSelector & 0x80); ulong result = 0; for (uint retry = 0; retry < 8; retry++) if (Sample(nmiMask, out ulong first) && Sample(nmiMask, out ulong second) && first == second) { result = Convert(second); break; } Native.Out8(0x70, originalSelector); Native.IrqRestore(flags); return result; } [UnmanagedCallersOnly(EntryPoint = "xfe_runtime_utc_filetime")] public static ulong FileTime() => ReadFileTime(); }