Exemple #1
0
 internal PMClock(PMTimer timer)
 {
     this.pmTimer          = timer;
     this.kernelTicksTotal = 0;
     this.pmResidual       = 0;
     this.pmLastUpdate     = pmTimer.Value;
 }
        internal static void ApicTimer(PMTimer pmTimer, ApicTimer apicTimer)
        {
            apicTimer.SetDivisor(1);
            apicTimer.SetOneShot();
            apicTimer.SetInterruptEnabled(false);
            apicTimer.SetInitialCount(~0u);

            uint apicLast = apicTimer.Value;
            uint pmLast   = pmTimer.Value;

            uint pmLimit = PMTimer.FrequencyHz / 15;
            uint pmAccum = 0;
            uint apicNow = 0;

            // Initial measurements
            apicLast = apicTimer.Value;
            pmLast   = pmTimer.Value;
            do
            {
                apicNow = apicTimer.Value;
                uint pmNow = pmTimer.Value | 0xff000000;
                pmAccum += PmDelta(pmNow, pmLast);
                pmLast   = pmNow;
            } while (pmAccum < pmLimit);

            ulong apicHz = PMTimer.FrequencyHz * (ulong)(apicLast - apicNow) / pmAccum;

            DebugStub.Print("Cpu{0}: APIC timer frequency {1} Hz\n",
                            __arglist(Processor.CurrentProcessor.Id, apicHz));

            apicTimer.SetBusFrequency((uint)apicHz);
        }
        internal static void CpuCycleCounter(PMTimer pmTimer)
        {
            uint  pmLast  = pmTimer.Value;
            ulong tscLast = Processor.CycleCount;

            uint  pmLimit = PMTimer.FrequencyHz / 15;
            uint  pmAccum = 0;
            ulong tscNow  = 0;

            // Initial measurements
            tscLast = Processor.CycleCount;
            pmLast  = pmTimer.Value;

            // Measurement loop
            do
            {
                tscNow = Processor.CycleCount;
                uint pmNow = pmTimer.Value;
                pmAccum += PmDelta(pmNow, pmLast);
                pmLast   = pmNow;
            } while (pmAccum < pmLimit);

            ulong tscHz = PMTimer.FrequencyHz * (tscNow - tscLast) / pmAccum;

            DebugStub.Print("Cpu{0}: TSC frequency {1} Hz\n",
                            __arglist(Processor.CurrentProcessor.Id, tscHz));
            Processor.CyclesPerSecond = tscHz;
        }
Exemple #4
0
        private void InitializeBsp(Processor rootProcessor)
        {
            DebugStub.Print("HalDevicesApic.Initialize()\n");

            pmTimer = AcpiTables.GetPMTimer();

            // Get PIC resources.  Pic is masked by default.
            PnpConfig picConfig
                = (PnpConfig)IoSystem.YieldResources("/pnp/PNP0000", typeof(PicStub));

            pic = new PicStub(picConfig);
            pic.Initialize(PicBaseVector);

            // Parse MP Table and create IO apics
            MpResources.ParseMpTables();
            ioApics = IoApic.CreateIOApics();

            halPic = new Apic(ioApics);
            halPic.Initialize(ApicBaseVector);

            // Apic timer is used to provide one-shot timer interrupts.
            halTimer = new ApicTimer(halPic);
            halTimer.Initialize();

            // Calibrate timers
            Calibrate.CpuCycleCounter(pmTimer);
            Calibrate.ApicTimer(pmTimer, halTimer);

            // Legacy timer is used to time stalls when starting CPUs.
            PnpConfig i8254Config
                = (PnpConfig)IoSystem.YieldResources("/pnp/PNP0100", typeof(Timer8254Apic));

            stallTimer = new Timer8254Apic(i8254Config);

            // Real-time clock
            PnpConfig rtClockConfig
                = (PnpConfig)IoSystem.YieldResources("/pnp/PNP0B00", typeof(RTClockApic));

            rtClock = new RTClockApic(rtClockConfig, halPic);

            // Compose our HalClock from the component clocks we have available
            halClock = new HalClockApic(halPic, rtClock, new PMClock(pmTimer));

            SystemClock.Initialize(halClock, TimeSpan.FromHours(8).Ticks);

            rootProcessor.AddPic(halPic);

            rootProcessor.AddTimer(halTimer.Interrupt, halTimer);
            rootProcessor.AddClock(halClock.Interrupt, halClock);

            InitializeProcessorCount();
            DebugReportProcessors();

            halTimer.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;

            halPic.DumpState();
            foreach (IoApic ioApic in ioApics)
            {
                ioApic.DumpRedirectionEntries();
            }
            pic.DumpRegisters();
        }
Exemple #5
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);
        }