public override void ReleaseResources() { clock.ReleaseResources(); clock = null; timer.ReleaseResources(); timer = null; pic.ReleaseResources(); pic = null; }
// Constructor internal RTClockLegacyPC(PnpConfig config, Pic pic, Timer8254LegacyPC timer) { DebugStub.Print("RTClock: create\n"); // /pnp/08/03/01/PNP0B00 0003 cfg dis : ISA RTC Controller : AT RTC // IRQ mask=0100 type=47 // I/O Port inf=01 min=0070 max=0070 aln=01 len=02 0070..0071 this.config = config; this.pic = pic; this.irq = ((IoIrqRange)config.DynamicRanges[1]).Irq; this.timer = timer; rtcadd = ((IoPortRange)config.DynamicRanges[0]) .PortAtOffset(0, 1, Access.ReadWrite); rtcdat = ((IoPortRange)config.DynamicRanges[0]) .PortAtOffset(1, 1, Access.ReadWrite); }
internal long GetKernelTicks(int pitNow) { int pitOffset = ComputePitOffset(this.pitLastClock, pitNow); long delta = Timer8254LegacyPC.PitTicksToTimeSpanTicks(pitOffset); long r = this.upTime + delta; if (r < this.lastKernelTicks) { // This should only be by a few ticks. // Something to look for if you are ever // working on this code. r = this.lastKernelTicks; } else { this.lastKernelTicks = r; } return(r); }
internal static void AddEntry(int who, RtcPitState rps, Timer8254LegacyPC timer, long cookie) { if (ignoreCount != 0) { ignoreCount--; return; } if (currentRecord == entries.Length) { return; } entries[currentRecord].who = who; entries[currentRecord].cookie = cookie; entries[currentRecord].when = Processor.CycleCount; int pitNow = timer.Timer2Read(); entries[currentRecord].currentTime = (ulong)rps.GetKernelTicks(pitNow); entries[currentRecord].upTime = rps.upTime; entries[currentRecord].pitLastClock = rps.pitLastClock; entries[currentRecord].pitNow = pitNow; currentRecord = currentRecord + 1; if (currentRecord == entries.Length) { bool iflag = Processor.DisableInterrupts(); try { DumpEntries(); DebugStub.Assert(false); } finally { Processor.RestoreInterrupts(iflag); } } }
internal static void AddEntry(int who, RtcPitState rps, Timer8254LegacyPC timer) { AddEntry(who, rps, timer, 0); }
public override void Initialize(Processor rootProcessor) { DebugStub.Print("HalDevices.Initialize() - Legacy\n"); pmTimer = AcpiTables.GetPMTimer(); // PIC PnpConfig picConfig = (PnpConfig)IoSystem.YieldResources("/pnp/PNP0000", typeof(Pic)); pic = new Pic(picConfig); pic.Initialize(); // Timer PnpConfig timerConfig = (PnpConfig)IoSystem.YieldResources("/pnp/PNP0100", typeof(Timer8254LegacyPC)); timer = new Timer8254LegacyPC(timerConfig, pic); byte timerInterrupt = timer.Initialize(); // Real-time clock PnpConfig clockConfig = (PnpConfig)IoSystem.YieldResources("/pnp/PNP0B00", typeof(RTClockLegacyPC)); clock = new RTClockLegacyPC(clockConfig, pic, timer); byte clockInterrupt = clock.Initialize(); bool noisyTimer = false; if (pmTimer != null) { noisyTimer = CalibrateTimers.Run(pmTimer, timer); } else { CalibrateTimers.Run(clock, timer); } clock.SetNoisyTimer(noisyTimer); clock.Start(); SystemClock.Initialize(clock, TimeSpan.FromHours(8).Ticks); rootProcessor.AddPic(pic); rootProcessor.AddTimer(timerInterrupt, timer); rootProcessor.AddClock(clockInterrupt, clock); // ---------------------------------------------------------- // Add Srat tables to the Processor halMemory = new HalMemorySrat(AcpiTables.GetSrat()); Processor.AddMemory(halMemory); timer.Start(); // Get the screen resources. Since we have metadata above to // declare all fixed resources used by the screen, // YieldResources("") will keep the resource tracking correct: halScreen = new HalScreenDirect(IoSystem.YieldResources("", typeof(HalScreen))); Console.Screen = (HalScreen)halScreen; }
internal static bool Run(PMTimer pmtimer, Timer8254LegacyPC i8254) { const int testRuns = 8; int attempts = 0; const uint pmMask = 0xffffffu; const ulong tscMask = 0xffffffffffff; const int i8254Mask = 0xffff; ulong [] tscHz = new ulong[testRuns]; ulong [] i8254Hz = new ulong[testRuns]; uint [] pmGoal = new uint[testRuns]; uint [] pmActual = new uint[testRuns]; i8254.Timer2Start(); measure: attempts++; for (uint i = 0; i < testRuns; i++) { uint testHz = 2u + (i % 5u); uint pmAccum = 0; uint pmLast = pmtimer.Value & pmMask; uint pmEnd = PMTimer.FrequencyHz / testHz; ulong tscStart = Processor.CycleCount; ulong tscEnd = 0; int i8254Accum = 0; int i8254Last = i8254.Timer2Read(); while (pmAccum < pmEnd) { // Spin to burn on few // clock cycles. On real hardware we stall // reading the timers. On VPC we see the // PMTimer go backwards occasionally when // hammering it so we call SpinWait to // reduce the chance of observing it go // backwards. // // Note: We explicitly use Thread.SpinWait // since it will not be optimized out, // unlike a simple spin loop. System.Threading.Thread.SpinWait(10000); uint pmNow = pmtimer.Value & pmMask; if (pmNow < pmLast) { // On VPC the PM // timer occasionally goes backwards and // this leads to bogus calibration // points. if (pmLast - pmNow < PMTimer.FrequencyHz / 2) { // ignore measurement continue; } // Clock wrap, measurement okay. } pmAccum += (pmNow + (pmMask + 1) - pmLast) & pmMask; pmLast = pmNow; tscEnd = Processor.CycleCount; int i8254Now = i8254.Timer2Read(); i8254Accum += ((i8254Mask + 1) + i8254Last - i8254Now) & i8254Mask; i8254Last = i8254Now; } ulong tscDelta = (tscEnd + (tscMask + 1) - tscStart) & tscMask; tscHz[i] = tscDelta * PMTimer.FrequencyHz / pmAccum; i8254Hz[i] = (ulong)i8254Accum * PMTimer.FrequencyHz / pmAccum; pmGoal[i] = pmEnd; pmActual[i] = pmAccum; } #region -*- temporary failure debugging support -*- ulong[] tscHzBackup = new ulong[tscHz.Length]; ulong[] i8254HzBackup = new ulong[i8254Hz.Length]; Array.Copy(tscHz, tscHzBackup, tscHz.Length); Array.Copy(i8254Hz, i8254HzBackup, i8254Hz.Length); #endregion Array.Sort(tscHz); Array.Sort(i8254Hz); bool noisyClock = false; // Re-measure if values are obviously bogus as can occur with // VPC. Check is minimum value is less than n% of maximum // value. bool tscFailed = tscHz[0] < 3 * tscHz[testRuns - 1] / 4; bool i8254Failed = i8254Hz[0] < 3 * i8254Hz[testRuns - 1] / 4; if (tscFailed || i8254Failed) { if (attempts < 10) { noisyClock = true; DebugStub.Print("CLOCK CALIBRATION FAILED"); if (tscFailed && i8254Failed) { DebugStub.Print(" (tsc and i2854) "); } else if (tscFailed) { DebugStub.Print(" (tsc only) "); } else { DebugStub.Print(" (i8254 only) "); } DebugStub.Print("RETRYING.\n"); for (int i = 0; i < tscHzBackup.Length; i++) { DebugStub.Print("tscHz {0} i8254Hz {1} pmGoal {2} pmActual {3}\n", __arglist(tscHzBackup[i], i8254HzBackup[i], pmGoal[i], pmActual[i])); } goto measure; } else { DebugStub.Print("ALL CLOCK CALIBRATION ATTEMPTS FAILED.\n"); // TODO: // Try to calibrate with rtClock // SlowCalibration(rtClock, timer8254); Processor.CyclesPerSecond = 1800 * 1000 * 1000; i8254.SetTicksPerSecond(1193180); return(true); } } ulong tscHzEstimate = tscHz[MinSpread(tscHz, 3)]; int i8254HzEstimate = (int)i8254Hz[MinSpread(i8254Hz, 3)]; DisplayResults(tscHzEstimate, i8254HzEstimate); // Set measured frequencies in appropriate places. Processor.CyclesPerSecond = tscHzEstimate; i8254.SetTicksPerSecond(i8254HzEstimate); // // Range of measurements is a pretty good indicator of VPCness // since it may have been descheduled during these measurements // so timer measurements will be poor. // int oValue = ApproxLog10(tscHzEstimate); int oRange = ApproxLog10(tscHz[testRuns - 1] - tscHz[0]); if (oValue - oRange < 5) { DebugStub.Print("*** Noisy timing measurements. Looks like measurement on VPC or bad hardware. ***\n"); noisyClock = true; } return(noisyClock); }
internal static void Run(RTClockLegacyPC rtc, Timer8254LegacyPC i8254) { // This test uses the RTC's update-in-progress bit, UIP, as // a measure of 1 second of time. The UIP set period is // around 240us which means we can safely read the // i8254 in a loop without worrying about missing the // bit being set / cleared because of i/o operations. // // This test fails horribly on VPC. It has problems with the // update-in-progress bit in the RTC. Fortunately we should // not get here on VPC. // // NB This routine does not try to be as rigorous as // the PM Timer version as each calibration run // takes much longer. const int testRuns = 2; int i8254Last = 0; int i8254Now = 0; int i8254Accum = 0; int [] i8254Hz = new int [testRuns]; ulong tscLast = 0; ulong tscNow = 0; ulong [] tscHz = new ulong[testRuns]; i8254.Timer2Start(); do { tscLast = Processor.CycleCount; i8254Last = i8254.Timer2Read(); } while (rtc.UpdateInProgress() == false); for (int i = 0; i < testRuns; i++) { while (rtc.UpdateInProgress() == true) { ; } do { tscNow = Processor.CycleCount; i8254Now = i8254.Timer2Read(); i8254Accum += (0x10000 + i8254Last - i8254Now) & 0xffff; i8254Last = i8254Now; }while (rtc.UpdateInProgress() == false); tscHz[i] = (tscNow + 0x1000000000000 - tscLast) & 0xffffffffffff; tscLast = tscNow; i8254Hz[i] = i8254Accum; i8254Accum = 0; } DisplayResults(tscHz[testRuns - 1], i8254Hz[testRuns - 1]); Processor.CyclesPerSecond = tscHz[testRuns - 1]; i8254.SetTicksPerSecond(i8254Hz[testRuns - 1]); }